{
  "openapi": "3.1.0",
  "info": {
    "title": "DevTools by Decussi API",
    "version": "1.0.0",
    "summary": "API aberta das ferramentas de desenvolvimento do DevTools by Decussi.",
    "description": "API pública do DevTools by Decussi: catálogo das 114 ferramentas, conteúdo das páginas em Markdown, diagnóstico de rede e SEO, consultas a bases públicas brasileiras e links temporários de compartilhamento.\n\nNão existe chave de API, cadastro ou OAuth. Os endpoints de leitura são abertos; os de escrita e os que consultam serviços externos exigem o token CSRF emitido por `GET /api/csrf`, porque são os mesmos endpoints usados pela interface do site.\n\nTodo erro sai no mesmo envelope JSON, com `code`, `message` e `hint`. A tabela completa está em https://dev-tools.decussi.com/developers#erros.\n\nConteúdo em português do Brasil. Instruções para agentes: https://dev-tools.decussi.com/AGENTS.md.",
    "contact": {
      "name": "Decussi",
      "url": "https://github.com/dudecussi"
    },
    "license": {
      "name": "Uso gratuito com atribuição",
      "url": "https://dev-tools.decussi.com/ai.txt"
    }
  },
  "servers": [
    {
      "url": "https://dev-tools.decussi.com",
      "description": "Produção"
    }
  ],
  "externalDocs": {
    "description": "Portal do desenvolvedor",
    "url": "https://dev-tools.decussi.com/developers"
  },
  "tags": [
    {
      "name": "Catálogo"
    },
    {
      "name": "Conteúdo"
    },
    {
      "name": "Rede"
    },
    {
      "name": "SEO"
    },
    {
      "name": "Brasil"
    },
    {
      "name": "Compartilhamento"
    },
    {
      "name": "Webhook"
    },
    {
      "name": "Sessão"
    },
    {
      "name": "Uso"
    }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "operationId": "getHealth",
        "tags": [
          "Catálogo"
        ],
        "summary": "Estado do serviço",
        "description": "Devolve o estado da aplicação, a quantidade de ferramentas publicadas e os endereços dos arquivos de descoberta. Não depende do banco de dados.",
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "exemplo": {
                    "value": {
                      "status": "ok",
                      "service": "DevTools by Decussi",
                      "tools": 109,
                      "openapi": "https://dev-tools.decussi.com/openapi.json"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s https://dev-tools.decussi.com/api/health"
          }
        ],
        "x-rate-limit-per-minute": 60
      }
    },
    "/api/tools": {
      "get": {
        "operationId": "listTools",
        "tags": [
          "Catálogo"
        ],
        "summary": "Lista as ferramentas do site",
        "description": "Catálogo completo em JSON: slug, nome, descrição, grupo, URL e se a ferramenta processa os dados no navegador. É o endpoint para descobrir qual página resolve um problema antes de mandar alguém para o site.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Busca por nome, descrição ou palavra-chave da ferramenta.",
            "schema": {
              "type": "string",
              "description": "Busca por nome, descrição ou palavra-chave da ferramenta.",
              "examples": [
                "cpf"
              ]
            }
          },
          {
            "name": "group",
            "in": "query",
            "required": false,
            "description": "Filtra por grupo.",
            "schema": {
              "type": "string",
              "description": "Filtra por grupo.",
              "enum": [
                "json",
                "security",
                "network",
                "text",
                "date",
                "web",
                "dev",
                "seo",
                "br"
              ],
              "examples": [
                "br"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Máximo de itens devolvidos (1 a 200).",
            "schema": {
              "type": "integer",
              "description": "Máximo de itens devolvidos (1 a 200).",
              "minimum": 1,
              "maximum": 200,
              "default": 200
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "exemplo": {
                    "value": {
                      "total": 2,
                      "tools": [
                        {
                          "slug": "validador-cpf",
                          "name": "Validador de CPF",
                          "description": "Valide CPF com dígito verificador",
                          "group": "br",
                          "category": "Brasil",
                          "url": "https://dev-tools.decussi.com/tools/br/validador-cpf",
                          "markdown_url": "https://dev-tools.decussi.com/tools/br/validador-cpf.md",
                          "runs_in_browser": true
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_parameter`: Parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_parameter": {
                    "value": {
                      "error": "Parâmetro inválido",
                      "code": "invalid_parameter",
                      "message": "Parâmetro inválido",
                      "hint": "Confira nome, tipo e formato dos campos enviados em /openapi.json.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s \"https://dev-tools.decussi.com/api/tools?q=cpf&limit=5\""
          }
        ],
        "x-rate-limit-per-minute": 60
      }
    },
    "/api/tools/{slug}": {
      "get": {
        "operationId": "getTool",
        "tags": [
          "Catálogo"
        ],
        "summary": "Detalha uma ferramenta",
        "description": "Traz a ficha da ferramenta: o que é, como usar, quando usar, perguntas frequentes e ferramentas relacionadas — o mesmo conteúdo da página, em JSON.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Identificador da ferramenta, como aparece na URL.",
            "schema": {
              "type": "string",
              "description": "Identificador da ferramenta, como aparece na URL.",
              "examples": [
                "json-viewer"
              ]
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: Recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "not_found": {
                    "value": {
                      "error": "Recurso não encontrado",
                      "code": "not_found",
                      "message": "Recurso não encontrado",
                      "hint": "Confira o identificador; links compartilhados expiram e somem depois do prazo.",
                      "status": 404,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s https://dev-tools.decussi.com/api/tools/json-viewer"
          }
        ],
        "x-rate-limit-per-minute": 60
      }
    },
    "/api/md": {
      "get": {
        "operationId": "getMarkdown",
        "tags": [
          "Conteúdo"
        ],
        "summary": "Versão em Markdown de uma página",
        "description": "Devolve qualquer página pública do site em Markdown, com um cabeçalho YAML de título, descrição e URL canônica. O mesmo conteúdo sai de qualquer URL do site com `Accept: text/markdown` ou com o sufixo `.md`.",
        "parameters": [
          {
            "name": "path",
            "in": "query",
            "required": true,
            "description": "Caminho da página no site, começando com barra.",
            "schema": {
              "type": "string",
              "description": "Caminho da página no site, começando com barra.",
              "examples": [
                "/tools/json/json-viewer"
              ]
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_parameter`: Parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_parameter": {
                    "value": {
                      "error": "Parâmetro inválido",
                      "code": "invalid_parameter",
                      "message": "Parâmetro inválido",
                      "hint": "Confira nome, tipo e formato dos campos enviados em /openapi.json.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: Recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "not_found": {
                    "value": {
                      "error": "Recurso não encontrado",
                      "code": "not_found",
                      "message": "Recurso não encontrado",
                      "hint": "Confira o identificador; links compartilhados expiram e somem depois do prazo.",
                      "status": 404,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s \"https://dev-tools.decussi.com/api/md?path=/tools/json/json-viewer\"\n\n# a mesma resposta, negociada na URL da própria página:\ncurl -s -H \"Accept: text/markdown\" https://dev-tools.decussi.com/tools/json/json-viewer"
          }
        ],
        "x-rate-limit-per-minute": 60
      }
    },
    "/api/openapi.json": {
      "get": {
        "operationId": "getOpenApiJson",
        "tags": [
          "Catálogo"
        ],
        "summary": "Esta especificação, em JSON",
        "description": "O mesmo documento publicado em /openapi.json, servido também sob /api para as ferramentas que procuram a especificação ao lado dos endpoints.",
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s https://dev-tools.decussi.com/api/openapi.json"
          }
        ],
        "x-rate-limit-per-minute": 60
      }
    },
    "/api/openapi.yaml": {
      "get": {
        "operationId": "getOpenApiYaml",
        "tags": [
          "Catálogo"
        ],
        "summary": "Esta especificação, em YAML",
        "description": "Mesma especificação em YAML. Também disponível em /openapi.yaml.",
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s https://dev-tools.decussi.com/api/openapi.yaml"
          }
        ],
        "x-rate-limit-per-minute": 60
      }
    },
    "/api/stats": {
      "get": {
        "operationId": "getStats",
        "tags": [
          "Uso"
        ],
        "summary": "Contagem de uso por ferramenta",
        "description": "Quantas vezes cada ferramenta foi usada, para ordenar recomendações.",
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "exemplo": {
                    "value": [
                      {
                        "tool_slug": "json-viewer",
                        "usage_count": 1234
                      }
                    ]
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s https://dev-tools.decussi.com/api/stats"
          }
        ],
        "x-rate-limit-per-minute": 30
      }
    },
    "/api/csrf": {
      "get": {
        "operationId": "getCsrfToken",
        "tags": [
          "Sessão"
        ],
        "summary": "Emite o token para os endpoints de escrita",
        "description": "Devolve um token e grava o cookie `csrf_token`. Os endpoints marcados com autenticação `csrf` exigem os dois: o cookie na requisição e o mesmo valor no cabeçalho `x-csrf-token`.",
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "exemplo": {
                    "value": {
                      "token": "3f2a…"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf"
          }
        ],
        "x-rate-limit-per-minute": 60
      }
    },
    "/api/infra/dns": {
      "post": {
        "operationId": "lookupDns",
        "tags": [
          "Rede"
        ],
        "summary": "Registros DNS de um domínio",
        "description": "Consulta A, AAAA, MX, TXT, NS, CNAME e SOA em uma chamada.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "Domínio a consultar. Protocolo e caminho são ignorados.",
                    "examples": [
                      "example.com"
                    ]
                  }
                },
                "required": [
                  "domain"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "exemplo": {
                    "value": {
                      "domain": "example.com",
                      "records": {
                        "A": [
                          "93.184.216.34"
                        ],
                        "MX": [],
                        "TXT": [
                          [
                            "v=spf1 -all"
                          ]
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_domain`: Domínio inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_domain": {
                    "value": {
                      "error": "Domínio inválido",
                      "code": "invalid_domain",
                      "message": "Domínio inválido",
                      "hint": "Envie só o domínio, como example.com — sem protocolo, porta ou caminho.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/infra/dns \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"domain\":\"example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/infra/ssl": {
      "post": {
        "operationId": "checkSsl",
        "tags": [
          "Rede"
        ],
        "summary": "Certificado SSL de um domínio",
        "description": "Emissor, validade, dias restantes e nomes alternativos do certificado.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "Domínio a verificar.",
                    "examples": [
                      "example.com"
                    ]
                  }
                },
                "required": [
                  "domain"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_domain`: Domínio inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_domain": {
                    "value": {
                      "error": "Domínio inválido",
                      "code": "invalid_domain",
                      "message": "Domínio inválido",
                      "hint": "Envie só o domínio, como example.com — sem protocolo, porta ou caminho.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/infra/ssl \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"domain\":\"example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/infra/whois": {
      "post": {
        "operationId": "lookupWhois",
        "tags": [
          "Rede"
        ],
        "summary": "Dados de WHOIS de um domínio",
        "description": "Registrante, datas de criação e expiração e servidores de nome.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "Domínio a consultar.",
                    "examples": [
                      "example.com"
                    ]
                  }
                },
                "required": [
                  "domain"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_domain`: Domínio inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_domain": {
                    "value": {
                      "error": "Domínio inválido",
                      "code": "invalid_domain",
                      "message": "Domínio inválido",
                      "hint": "Envie só o domínio, como example.com — sem protocolo, porta ou caminho.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/infra/whois \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"domain\":\"example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/infra/headers": {
      "post": {
        "operationId": "getHttpHeaders",
        "tags": [
          "Rede"
        ],
        "summary": "Cabeçalhos HTTP de uma URL",
        "description": "Faz a requisição e devolve os cabeçalhos da resposta. Endereços internos e IPs privados são recusados.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "URL http(s) pública.",
                    "examples": [
                      "https://example.com"
                    ]
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_url`: URL inválida · `blocked_host`: Endereço não permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_url": {
                    "value": {
                      "error": "URL inválida",
                      "code": "invalid_url",
                      "message": "URL inválida",
                      "hint": "Envie uma URL http(s) pública e completa, como https://example.com/pagina.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "blocked_host": {
                    "value": {
                      "error": "Endereço não permitido",
                      "code": "blocked_host",
                      "message": "Endereço não permitido",
                      "hint": "Endereços internos, localhost e IPs privados são bloqueados por segurança.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/infra/headers \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"url\":\"https://example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/infra/http-client": {
      "post": {
        "operationId": "sendHttpRequest",
        "tags": [
          "Rede"
        ],
        "summary": "Cliente HTTP (proxy de teste)",
        "description": "Executa uma requisição HTTP a partir do servidor e devolve status, tempo, cabeçalhos e corpo. Só endereços públicos; o destino é revalidado depois de cada redirecionamento.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "URL de destino.",
                    "examples": [
                      "https://example.com"
                    ]
                  },
                  "method": {
                    "type": "string",
                    "description": "Método HTTP.",
                    "enum": [
                      "GET",
                      "POST",
                      "PUT",
                      "PATCH",
                      "DELETE",
                      "HEAD",
                      "OPTIONS"
                    ],
                    "default": "GET"
                  },
                  "headers": {
                    "type": "object",
                    "description": "Cabeçalhos extras, como pares nome/valor."
                  },
                  "body": {
                    "type": "string",
                    "description": "Corpo da requisição, quando o método aceita."
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_method`: Método HTTP não suportado · `blocked_host`: Endereço não permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_method": {
                    "value": {
                      "error": "Método HTTP não suportado",
                      "code": "invalid_method",
                      "message": "Método HTTP não suportado",
                      "hint": "Use um dos métodos listados para o endpoint em /openapi.json.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "blocked_host": {
                    "value": {
                      "error": "Endereço não permitido",
                      "code": "blocked_host",
                      "message": "Endereço não permitido",
                      "hint": "Endereços internos, localhost e IPs privados são bloqueados por segurança.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`upstream_error`: Serviço externo indisponível no momento",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "upstream_error": {
                    "value": {
                      "error": "Serviço externo indisponível no momento",
                      "code": "upstream_error",
                      "message": "Serviço externo indisponível no momento",
                      "hint": "A falha é do serviço consultado. Tente de novo em alguns minutos.",
                      "status": 502,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "description": "`upstream_timeout`: Tempo esgotado na consulta",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "upstream_timeout": {
                    "value": {
                      "error": "Tempo esgotado na consulta",
                      "code": "upstream_timeout",
                      "message": "Tempo esgotado na consulta",
                      "hint": "O serviço consultado demorou demais. Repita a requisição mais tarde.",
                      "status": 504,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/infra/http-client \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"url\":\"https://example.com\",\"method\":\"GET\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/infra/port": {
      "post": {
        "operationId": "checkPort",
        "tags": [
          "Rede"
        ],
        "summary": "Testa uma porta TCP",
        "description": "Abre uma conexão TCP e informa se a porta responde, com o tempo gasto.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "host": {
                    "type": "string",
                    "description": "Domínio ou IP público.",
                    "examples": [
                      "example.com"
                    ]
                  },
                  "port": {
                    "type": "integer",
                    "description": "Porta de 1 a 65535.",
                    "minimum": 1,
                    "maximum": 65535,
                    "examples": [
                      443
                    ]
                  }
                },
                "required": [
                  "host",
                  "port"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_host`: Host inválido · `invalid_port`: Porta inválida · `blocked_host`: Endereço não permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_host": {
                    "value": {
                      "error": "Host inválido",
                      "code": "invalid_host",
                      "message": "Host inválido",
                      "hint": "Use um domínio ou um IP público; endereços privados são recusados.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "invalid_port": {
                    "value": {
                      "error": "Porta inválida",
                      "code": "invalid_port",
                      "message": "Porta inválida",
                      "hint": "Envie um número inteiro entre 1 e 65535.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "blocked_host": {
                    "value": {
                      "error": "Endereço não permitido",
                      "code": "blocked_host",
                      "message": "Endereço não permitido",
                      "hint": "Endereços internos, localhost e IPs privados são bloqueados por segurança.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/infra/port \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"host\":\"example.com\",\"port\":443}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/infra/ping": {
      "post": {
        "operationId": "pingHost",
        "tags": [
          "Rede"
        ],
        "summary": "Latência até um host",
        "description": "Mede o tempo de resposta de uma conexão TCP, em várias tentativas.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "host": {
                    "type": "string",
                    "description": "Domínio ou IP público.",
                    "examples": [
                      "example.com"
                    ]
                  },
                  "port": {
                    "type": "integer",
                    "description": "Porta usada na medição.",
                    "minimum": 1,
                    "maximum": 65535,
                    "default": 443
                  }
                },
                "required": [
                  "host"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_host`: Host inválido · `invalid_port`: Porta inválida · `blocked_host`: Endereço não permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_host": {
                    "value": {
                      "error": "Host inválido",
                      "code": "invalid_host",
                      "message": "Host inválido",
                      "hint": "Use um domínio ou um IP público; endereços privados são recusados.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "invalid_port": {
                    "value": {
                      "error": "Porta inválida",
                      "code": "invalid_port",
                      "message": "Porta inválida",
                      "hint": "Envie um número inteiro entre 1 e 65535.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "blocked_host": {
                    "value": {
                      "error": "Endereço não permitido",
                      "code": "blocked_host",
                      "message": "Endereço não permitido",
                      "hint": "Endereços internos, localhost e IPs privados são bloqueados por segurança.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/infra/ping \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"host\":\"example.com\",\"port\":443}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/infra/ip": {
      "post": {
        "operationId": "lookupIp",
        "tags": [
          "Rede"
        ],
        "summary": "Geolocalização e provedor de um IP",
        "description": "País, região, cidade, provedor e ASN de um endereço IP público.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ip": {
                    "type": "string",
                    "description": "IPv4 ou IPv6 público.",
                    "examples": [
                      "8.8.8.8"
                    ]
                  }
                },
                "required": [
                  "ip"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_ip`: IP inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_ip": {
                    "value": {
                      "error": "IP inválido",
                      "code": "invalid_ip",
                      "message": "IP inválido",
                      "hint": "Envie um IPv4 ou IPv6 público, sem máscara nem porta.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: Recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "not_found": {
                    "value": {
                      "error": "Recurso não encontrado",
                      "code": "not_found",
                      "message": "Recurso não encontrado",
                      "hint": "Confira o identificador; links compartilhados expiram e somem depois do prazo.",
                      "status": 404,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/infra/ip \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"ip\":\"8.8.8.8\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/infra/email": {
      "post": {
        "operationId": "diagnoseEmailDomain",
        "tags": [
          "Rede"
        ],
        "summary": "SPF, DKIM, DMARC e MX de um domínio",
        "description": "Diagnóstico dos registros que decidem a entregabilidade de e-mail.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "Domínio a diagnosticar.",
                    "examples": [
                      "example.com"
                    ]
                  }
                },
                "required": [
                  "domain"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_domain`: Domínio inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_domain": {
                    "value": {
                      "error": "Domínio inválido",
                      "code": "invalid_domain",
                      "message": "Domínio inválido",
                      "hint": "Envie só o domínio, como example.com — sem protocolo, porta ou caminho.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/infra/email \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"domain\":\"example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/seo/meta": {
      "post": {
        "operationId": "getMetaTags",
        "tags": [
          "SEO"
        ],
        "summary": "Meta tags e Open Graph de uma página",
        "description": "Title, description, canonical, Open Graph e Twitter Cards da URL informada.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "URL da página.",
                    "examples": [
                      "https://example.com"
                    ]
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_url`: URL inválida · `blocked_host`: Endereço não permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_url": {
                    "value": {
                      "error": "URL inválida",
                      "code": "invalid_url",
                      "message": "URL inválida",
                      "hint": "Envie uma URL http(s) pública e completa, como https://example.com/pagina.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "blocked_host": {
                    "value": {
                      "error": "Endereço não permitido",
                      "code": "blocked_host",
                      "message": "Endereço não permitido",
                      "hint": "Endereços internos, localhost e IPs privados são bloqueados por segurança.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/seo/meta \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"url\":\"https://example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/seo/robots": {
      "post": {
        "operationId": "checkRobots",
        "tags": [
          "SEO"
        ],
        "summary": "Lê e interpreta um robots.txt",
        "description": "Busca o robots.txt do domínio e separa as regras por user-agent.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "URL do site ou do próprio robots.txt.",
                    "examples": [
                      "https://example.com"
                    ]
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_url`: URL inválida · `blocked_host`: Endereço não permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_url": {
                    "value": {
                      "error": "URL inválida",
                      "code": "invalid_url",
                      "message": "URL inválida",
                      "hint": "Envie uma URL http(s) pública e completa, como https://example.com/pagina.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "blocked_host": {
                    "value": {
                      "error": "Endereço não permitido",
                      "code": "blocked_host",
                      "message": "Endereço não permitido",
                      "hint": "Endereços internos, localhost e IPs privados são bloqueados por segurança.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/seo/robots \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"url\":\"https://example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/seo/sitemap": {
      "post": {
        "operationId": "validateSitemap",
        "tags": [
          "SEO"
        ],
        "summary": "Valida um sitemap.xml",
        "description": "Confere a estrutura do sitemap, conta as URLs e aponta problemas.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "URL do sitemap.",
                    "examples": [
                      "https://example.com/sitemap.xml"
                    ]
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_url`: URL inválida · `blocked_host`: Endereço não permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_url": {
                    "value": {
                      "error": "URL inválida",
                      "code": "invalid_url",
                      "message": "URL inválida",
                      "hint": "Envie uma URL http(s) pública e completa, como https://example.com/pagina.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "blocked_host": {
                    "value": {
                      "error": "Endereço não permitido",
                      "code": "blocked_host",
                      "message": "Endereço não permitido",
                      "hint": "Endereços internos, localhost e IPs privados são bloqueados por segurança.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/seo/sitemap \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"url\":\"https://example.com/sitemap.xml\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/seo/validate": {
      "post": {
        "operationId": "validateSeo",
        "tags": [
          "SEO"
        ],
        "summary": "Auditoria de SEO on-page",
        "description": "Analisa title, meta, headings, imagens, links, dados estruturados e desempenho declarado da página.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "URL da página a auditar.",
                    "examples": [
                      "https://example.com"
                    ]
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_url`: URL inválida · `blocked_host`: Endereço não permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_url": {
                    "value": {
                      "error": "URL inválida",
                      "code": "invalid_url",
                      "message": "URL inválida",
                      "hint": "Envie uma URL http(s) pública e completa, como https://example.com/pagina.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "blocked_host": {
                    "value": {
                      "error": "Endereço não permitido",
                      "code": "blocked_host",
                      "message": "Endereço não permitido",
                      "hint": "Endereços internos, localhost e IPs privados são bloqueados por segurança.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/seo/validate \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"url\":\"https://example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/seo/redirects": {
      "post": {
        "operationId": "checkRedirects",
        "tags": [
          "SEO"
        ],
        "summary": "Cadeia de redirecionamentos",
        "description": "Segue os redirecionamentos salto a salto, sem deixar o cliente resolver, e sonda as quatro variantes de www e protocolo para revelar conteúdo servido em mais de um endereço.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "URL de partida da cadeia.",
                    "examples": [
                      "https://example.com"
                    ]
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_url`: URL inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_url": {
                    "value": {
                      "error": "URL inválida",
                      "code": "invalid_url",
                      "message": "URL inválida",
                      "hint": "Envie uma URL http(s) pública e completa, como https://example.com/pagina.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/seo/redirects \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"url\":\"https://example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/seo/densidade": {
      "post": {
        "operationId": "densidadePalavras",
        "tags": [
          "SEO"
        ],
        "summary": "Densidade de palavras de uma página",
        "description": "Extrai o texto visível da página e devolve as palavras e as expressões de duas e três palavras mais frequentes, com a densidade de cada uma.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "URL da página a analisar.",
                    "examples": [
                      "https://example.com"
                    ]
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_url`: URL inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_url": {
                    "value": {
                      "error": "URL inválida",
                      "code": "invalid_url",
                      "message": "URL inválida",
                      "hint": "Envie uma URL http(s) pública e completa, como https://example.com/pagina.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`upstream_error`: Serviço externo indisponível no momento",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "upstream_error": {
                    "value": {
                      "error": "Serviço externo indisponível no momento",
                      "code": "upstream_error",
                      "message": "Serviço externo indisponível no momento",
                      "hint": "A falha é do serviço consultado. Tente de novo em alguns minutos.",
                      "status": 502,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/seo/densidade \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"url\":\"https://example.com\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/br/cep": {
      "post": {
        "operationId": "lookupCep",
        "tags": [
          "Brasil"
        ],
        "summary": "Endereço a partir do CEP",
        "description": "Consulta o ViaCEP e devolve logradouro, bairro, cidade, UF, IBGE e DDD.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cep": {
                    "type": "string",
                    "description": "CEP com 8 dígitos. Pontuação é ignorada.",
                    "examples": [
                      "01001000"
                    ]
                  }
                },
                "required": [
                  "cep"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "exemplo": {
                    "value": {
                      "cep": "01001-000",
                      "logradouro": "Praça da Sé",
                      "bairro": "Sé",
                      "cidade": "São Paulo",
                      "uf": "SP"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_document`: Documento inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_document": {
                    "value": {
                      "error": "Documento inválido",
                      "code": "invalid_document",
                      "message": "Documento inválido",
                      "hint": "Confira a quantidade de dígitos e os dígitos verificadores antes de reenviar.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: Recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "not_found": {
                    "value": {
                      "error": "Recurso não encontrado",
                      "code": "not_found",
                      "message": "Recurso não encontrado",
                      "hint": "Confira o identificador; links compartilhados expiram e somem depois do prazo.",
                      "status": 404,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`upstream_error`: Serviço externo indisponível no momento",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "upstream_error": {
                    "value": {
                      "error": "Serviço externo indisponível no momento",
                      "code": "upstream_error",
                      "message": "Serviço externo indisponível no momento",
                      "hint": "A falha é do serviço consultado. Tente de novo em alguns minutos.",
                      "status": 502,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "description": "`upstream_timeout`: Tempo esgotado na consulta",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "upstream_timeout": {
                    "value": {
                      "error": "Tempo esgotado na consulta",
                      "code": "upstream_timeout",
                      "message": "Tempo esgotado na consulta",
                      "hint": "O serviço consultado demorou demais. Repita a requisição mais tarde.",
                      "status": 504,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/br/cep \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"cep\":\"01001000\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/br/cnpj": {
      "post": {
        "operationId": "lookupCnpj",
        "tags": [
          "Brasil"
        ],
        "summary": "Dados cadastrais de um CNPJ",
        "description": "Valida os dígitos verificadores antes de consultar a BrasilAPI, e devolve razão social, situação, CNAE, endereço e sócios.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cnpj": {
                    "type": "string",
                    "description": "CNPJ com 14 dígitos. Pontuação é ignorada.",
                    "examples": [
                      "00000000000191"
                    ]
                  }
                },
                "required": [
                  "cnpj"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_document`: Documento inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_document": {
                    "value": {
                      "error": "Documento inválido",
                      "code": "invalid_document",
                      "message": "Documento inválido",
                      "hint": "Confira a quantidade de dígitos e os dígitos verificadores antes de reenviar.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: Recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "not_found": {
                    "value": {
                      "error": "Recurso não encontrado",
                      "code": "not_found",
                      "message": "Recurso não encontrado",
                      "hint": "Confira o identificador; links compartilhados expiram e somem depois do prazo.",
                      "status": 404,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "`upstream_error`: Serviço externo indisponível no momento",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "upstream_error": {
                    "value": {
                      "error": "Serviço externo indisponível no momento",
                      "code": "upstream_error",
                      "message": "Serviço externo indisponível no momento",
                      "hint": "A falha é do serviço consultado. Tente de novo em alguns minutos.",
                      "status": 502,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "description": "`upstream_timeout`: Tempo esgotado na consulta",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "upstream_timeout": {
                    "value": {
                      "error": "Tempo esgotado na consulta",
                      "code": "upstream_timeout",
                      "message": "Tempo esgotado na consulta",
                      "hint": "O serviço consultado demorou demais. Repita a requisição mais tarde.",
                      "status": 504,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/br/cnpj \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"cnpj\":\"00000000000191\"}'"
          }
        ],
        "x-rate-limit-per-minute": 15
      }
    },
    "/api/share": {
      "post": {
        "operationId": "createShare",
        "tags": [
          "Compartilhamento"
        ],
        "summary": "Cria um link temporário de texto",
        "description": "Guarda um texto e devolve uma URL curta que expira sozinha. Use para entregar um log, um trecho de código ou um resultado sem anexar arquivo.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {
                    "type": "string",
                    "description": "Texto a compartilhar.",
                    "maxLength": 500000
                  },
                  "expiresInHours": {
                    "type": "integer",
                    "description": "Validade em horas.",
                    "minimum": 1,
                    "maximum": 168,
                    "default": 2
                  },
                  "slug": {
                    "type": "string",
                    "description": "Identificador personalizado: letras, números, - e _ (até 16).",
                    "examples": [
                      "meu-log"
                    ]
                  }
                },
                "required": [
                  "content"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "exemplo": {
                    "value": {
                      "id": "a1b2c3",
                      "url": "https://dev-tools.decussi.com/s/a1b2c3",
                      "expiresAt": "2026-09-04T21:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_parameter`: Parâmetro inválido · `invalid_id`: ID inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_parameter": {
                    "value": {
                      "error": "Parâmetro inválido",
                      "code": "invalid_parameter",
                      "message": "Parâmetro inválido",
                      "hint": "Confira nome, tipo e formato dos campos enviados em /openapi.json.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  },
                  "invalid_id": {
                    "value": {
                      "error": "ID inválido",
                      "code": "invalid_id",
                      "message": "ID inválido",
                      "hint": "Use o identificador devolvido na criação do recurso, sem alterações.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "409": {
            "description": "`conflict`: Conflito com um recurso existente",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "conflict": {
                    "value": {
                      "error": "Conflito com um recurso existente",
                      "code": "conflict",
                      "message": "Conflito com um recurso existente",
                      "hint": "Escolha outro identificador ou aguarde o recurso atual expirar.",
                      "status": 409,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: Payload excede o limite permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "payload_too_large": {
                    "value": {
                      "error": "Payload excede o limite permitido",
                      "code": "payload_too_large",
                      "message": "Payload excede o limite permitido",
                      "hint": "Reduza o conteúdo enviado; o limite de cada endpoint está em /openapi.json.",
                      "status": 413,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/share \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"content\":\"log da build\",\"expiresInHours\":2}'"
          }
        ],
        "x-rate-limit-per-minute": 20
      }
    },
    "/api/share/{id}": {
      "get": {
        "operationId": "getShare",
        "tags": [
          "Compartilhamento"
        ],
        "summary": "Lê um link temporário",
        "description": "Devolve o conteúdo enquanto o link estiver válido. Com `?format=plain` (ou `Accept: text/plain`) a resposta é o texto puro, sem envelope.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identificador do link.",
            "schema": {
              "type": "string",
              "description": "Identificador do link.",
              "examples": [
                "a1b2c3"
              ]
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Use `plain` para receber só o texto.",
            "schema": {
              "type": "string",
              "description": "Use `plain` para receber só o texto.",
              "enum": [
                "plain"
              ]
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_id`: ID inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_id": {
                    "value": {
                      "error": "ID inválido",
                      "code": "invalid_id",
                      "message": "ID inválido",
                      "hint": "Use o identificador devolvido na criação do recurso, sem alterações.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: Recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "not_found": {
                    "value": {
                      "error": "Recurso não encontrado",
                      "code": "not_found",
                      "message": "Recurso não encontrado",
                      "hint": "Confira o identificador; links compartilhados expiram e somem depois do prazo.",
                      "status": 404,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s https://dev-tools.decussi.com/api/share/a1b2c3"
          }
        ],
        "x-rate-limit-per-minute": 60
      }
    },
    "/api/share/encrypted": {
      "post": {
        "operationId": "createEncryptedShare",
        "tags": [
          "Compartilhamento"
        ],
        "summary": "Cria um link criptografado",
        "description": "Guarda um conteúdo já criptografado no navegador. O servidor nunca vê a senha nem o texto claro; a chave viaja no fragmento da URL.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "encryptedContent": {
                    "type": "string",
                    "description": "Conteúdo cifrado no cliente.",
                    "maxLength": 500000
                  },
                  "expiresInHours": {
                    "type": "integer",
                    "description": "Validade em horas.",
                    "minimum": 1,
                    "maximum": 168,
                    "default": 2
                  }
                },
                "required": [
                  "encryptedContent"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_parameter`: Parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_parameter": {
                    "value": {
                      "error": "Parâmetro inválido",
                      "code": "invalid_parameter",
                      "message": "Parâmetro inválido",
                      "hint": "Confira nome, tipo e formato dos campos enviados em /openapi.json.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: Payload excede o limite permitido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "payload_too_large": {
                    "value": {
                      "error": "Payload excede o limite permitido",
                      "code": "payload_too_large",
                      "message": "Payload excede o limite permitido",
                      "hint": "Reduza o conteúdo enviado; o limite de cada endpoint está em /openapi.json.",
                      "status": 413,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/share/encrypted \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"encryptedContent\":\"U2FsdGVkX1…\"}'"
          }
        ],
        "x-rate-limit-per-minute": 20
      }
    },
    "/api/share/encrypted/{id}": {
      "get": {
        "operationId": "getEncryptedShare",
        "tags": [
          "Compartilhamento"
        ],
        "summary": "Lê um link criptografado",
        "description": "Devolve o conteúdo cifrado. A descriptografia acontece no cliente.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identificador do link.",
            "schema": {
              "type": "string",
              "description": "Identificador do link.",
              "examples": [
                "a1b2c3"
              ]
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_id`: ID inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_id": {
                    "value": {
                      "error": "ID inválido",
                      "code": "invalid_id",
                      "message": "ID inválido",
                      "hint": "Use o identificador devolvido na criação do recurso, sem alterações.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: Recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "not_found": {
                    "value": {
                      "error": "Recurso não encontrado",
                      "code": "not_found",
                      "message": "Recurso não encontrado",
                      "hint": "Confira o identificador; links compartilhados expiram e somem depois do prazo.",
                      "status": 404,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s https://dev-tools.decussi.com/api/share/encrypted/a1b2c3"
          }
        ],
        "x-rate-limit-per-minute": 60
      }
    },
    "/api/webhook": {
      "post": {
        "operationId": "createWebhookBin",
        "tags": [
          "Webhook"
        ],
        "summary": "Cria uma URL temporária de webhook",
        "description": "Devolve uma URL que aceita qualquer método e grava as requisições recebidas por 24 horas.",
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "exemplo": {
                    "value": {
                      "id": "Ab3xY",
                      "expiresAt": "2026-09-05T18:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/webhook -H \"x-csrf-token: $TOKEN\""
          }
        ],
        "x-rate-limit-per-minute": 20
      }
    },
    "/api/webhook/{id}/requests": {
      "get": {
        "operationId": "listWebhookRequests",
        "tags": [
          "Webhook"
        ],
        "summary": "Lista o que chegou na URL de webhook",
        "description": "Método, cabeçalhos, query, corpo e horário de cada requisição recebida.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identificador da URL de webhook.",
            "schema": {
              "type": "string",
              "description": "Identificador da URL de webhook.",
              "examples": [
                "Ab3xY"
              ]
            }
          }
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_id`: ID inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_id": {
                    "value": {
                      "error": "ID inválido",
                      "code": "invalid_id",
                      "message": "ID inválido",
                      "hint": "Use o identificador devolvido na criação do recurso, sem alterações.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: Recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "not_found": {
                    "value": {
                      "error": "Recurso não encontrado",
                      "code": "not_found",
                      "message": "Recurso não encontrado",
                      "hint": "Confira o identificador; links compartilhados expiram e somem depois do prazo.",
                      "status": 404,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -s https://dev-tools.decussi.com/api/webhook/Ab3xY/requests"
          }
        ],
        "x-rate-limit-per-minute": 60
      },
      "delete": {
        "operationId": "clearWebhookRequests",
        "tags": [
          "Webhook"
        ],
        "summary": "Apaga o que foi recebido",
        "description": "Esvazia a lista de requisições da URL de webhook, sem apagar a URL.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identificador da URL de webhook.",
            "schema": {
              "type": "string",
              "description": "Identificador da URL de webhook.",
              "examples": [
                "Ab3xY"
              ]
            }
          }
        ],
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_id`: ID inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_id": {
                    "value": {
                      "error": "ID inválido",
                      "code": "invalid_id",
                      "message": "ID inválido",
                      "hint": "Use o identificador devolvido na criação do recurso, sem alterações.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X DELETE https://dev-tools.decussi.com/api/webhook/Ab3xY/requests -H \"x-csrf-token: $TOKEN\""
          }
        ],
        "x-rate-limit-per-minute": 20
      }
    },
    "/api/usage": {
      "post": {
        "operationId": "registerToolUsage",
        "tags": [
          "Uso"
        ],
        "summary": "Registra o uso de uma ferramenta",
        "description": "Incrementa o contador exibido na página inicial. Não guarda nada do conteúdo.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "toolSlug": {
                    "type": "string",
                    "description": "Slug da ferramenta usada.",
                    "examples": [
                      "json-viewer"
                    ]
                  }
                },
                "required": [
                  "toolSlug"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "csrfToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "headers": {
              "X-RateLimit-Limit": {
                "description": "Teto de requisições por minuto para este IP.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requisições restantes na janela atual.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_parameter`: Parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "invalid_parameter": {
                    "value": {
                      "error": "Parâmetro inválido",
                      "code": "invalid_parameter",
                      "message": "Parâmetro inválido",
                      "hint": "Confira nome, tipo e formato dos campos enviados em /openapi.json.",
                      "status": 400,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "`csrf_token_invalid`: Token de segurança inválido. Recarregue a página e tente novamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "csrf_token_invalid": {
                    "value": {
                      "error": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "code": "csrf_token_invalid",
                      "message": "Token de segurança inválido. Recarregue a página e tente novamente.",
                      "hint": "Chame GET /api/csrf, guarde o cookie csrf_token e reenvie o valor no cabeçalho x-csrf-token.",
                      "status": 403,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`: método diferente do documentado. A resposta traz o cabeçalho Allow.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: Muitas requisições. Tente novamente em alguns minutos.",
            "headers": {
              "Retry-After": {
                "description": "Segundos a esperar antes de repetir a requisição.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "rate_limited": {
                    "value": {
                      "error": "Muitas requisições. Tente novamente em alguns minutos.",
                      "code": "rate_limited",
                      "message": "Muitas requisições. Tente novamente em alguns minutos.",
                      "hint": "Espere os segundos indicados em Retry-After antes de repetir a requisição.",
                      "status": 429,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`: Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErroApi"
                },
                "examples": {
                  "internal_error": {
                    "value": {
                      "error": "Erro interno",
                      "code": "internal_error",
                      "message": "Erro interno",
                      "hint": "Tente de novo em instantes; se persistir, relate em github.com/dudecussi.",
                      "status": 500,
                      "documentation_url": "https://dev-tools.decussi.com/developers#erros"
                    }
                  }
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "TOKEN=$(curl -sc /tmp/dt.cookie https://dev-tools.decussi.com/api/csrf | sed 's/.*\"token\":\"\\([^\"]*\\)\".*/\\1/')\ncurl -sb /tmp/dt.cookie -X POST https://dev-tools.decussi.com/api/usage \\\n  -H \"Content-Type: application/json\" \\\n  -H \"x-csrf-token: $TOKEN\" \\\n  -d '{\"toolSlug\":\"json-viewer\"}'"
          }
        ],
        "x-rate-limit-per-minute": 30
      }
    }
  },
  "components": {
    "securitySchemes": {
      "csrfToken": {
        "type": "apiKey",
        "in": "header",
        "name": "x-csrf-token",
        "description": "Token emitido por GET /api/csrf. O cookie `csrf_token` da mesma resposta precisa voltar na requisição."
      }
    },
    "schemas": {
      "ErroApi": {
        "type": "object",
        "description": "Envelope único de erro. `error` repete `message` e existe por compatibilidade com a interface do site.",
        "required": [
          "error",
          "code",
          "message",
          "hint",
          "status",
          "documentation_url"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Mensagem legível (compatibilidade)."
          },
          "code": {
            "type": "string",
            "description": "Código estável do erro.",
            "enum": [
              "invalid_request",
              "invalid_parameter",
              "invalid_domain",
              "invalid_url",
              "invalid_host",
              "invalid_port",
              "invalid_ip",
              "invalid_email",
              "invalid_document",
              "invalid_id",
              "invalid_method",
              "blocked_host",
              "unauthorized",
              "csrf_token_invalid",
              "not_found",
              "endpoint_not_found",
              "method_not_allowed",
              "not_acceptable",
              "conflict",
              "payload_too_large",
              "rate_limited",
              "internal_error",
              "upstream_error",
              "upstream_timeout"
            ]
          },
          "message": {
            "type": "string",
            "description": "Mensagem legível."
          },
          "hint": {
            "type": "string",
            "description": "O que fazer para a próxima tentativa dar certo."
          },
          "status": {
            "type": "integer",
            "description": "Status HTTP repetido no corpo."
          },
          "documentation_url": {
            "type": "string",
            "format": "uri",
            "description": "Tabela de erros no portal do desenvolvedor."
          }
        }
      }
    }
  }
}