{
  "openapi": "3.1.0",
  "info": {
    "title": "Capitalis API — contrato público",
    "version": "1.0.0",
    "description": "Contrato **público** da plataforma Capitalis (Factoring as a Service). Documenta apenas os endpoints abertos a qualquer cliente: saúde, versão, estado operacional da plataforma e o formulário de contato do site.\n\nO restante da API — operações, cadastros, financeiro, cobrança, trustee — e o servidor MCP são liberados a cliente com contrato ativo, junto das credenciais, pelo canal comercial (comercial@sistemacapitalis.com.br). Não há cadastro self-service de chave: chamar `/api/*` sem credencial devolve 401.\n\nGuia para agentes: https://www.sistemacapitalis.com.br/llms.txt · Portal do desenvolvedor: https://www.sistemacapitalis.com.br/developers",
    "contact": {
      "name": "Capitalis",
      "url": "https://www.sistemacapitalis.com.br/contact",
      "email": "comercial@sistemacapitalis.com.br"
    },
    "license": {
      "name": "Proprietário, uso mediante contrato de assinatura"
    }
  },
  "servers": [
    {
      "url": "https://www.sistemacapitalis.com.br/api",
      "description": "Produção (mesma origem do site)"
    }
  ],
  "externalDocs": {
    "description": "Portal do desenvolvedor",
    "url": "https://www.sistemacapitalis.com.br/developers"
  },
  "paths": {
    "/health": {
      "get": {
        "tags": [
          "infra"
        ],
        "summary": "Health",
        "description": "Liveness: responde rápido, sem tocar o banco (não derruba o container num blip do DB).",
        "operationId": "health_health_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/health/ready": {
      "get": {
        "tags": [
          "infra"
        ],
        "summary": "Readiness",
        "description": "Readiness: confirma conectividade com o Postgres (SELECT 1). 503 se o banco falhar.",
        "operationId": "readiness_health_ready_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/version": {
      "get": {
        "tags": [
          "infra"
        ],
        "summary": "Version",
        "operationId": "version_version_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersionOut"
                }
              }
            }
          }
        }
      }
    },
    "/status": {
      "get": {
        "tags": [
          "status"
        ],
        "summary": "Status Publico",
        "operationId": "status_publico_status_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusOut"
                }
              }
            }
          }
        }
      }
    },
    "/site/contato": {
      "post": {
        "tags": [
          "site"
        ],
        "summary": "Contato",
        "description": "Recebe o formulário do site e entrega na caixa certa.\n\nDevolve **202** (aceito) e não 200: o e-mail é entregue ao Resend, que o repassa —\na confirmação de entrega na caixa é assíncrona e não cabe na resposta.",
        "operationId": "contato_site_contato_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContatoIn"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContatoOut"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/site/contato/assuntos": {
      "get": {
        "tags": [
          "site"
        ],
        "summary": "Assuntos",
        "description": "Os assuntos aceitos, para o site montar o seletor sem duplicar a lista.\n\nExiste para que a lista viva num lugar só: se um assunto entrar aqui e o HTML não\nsouber, o formulário continua funcionando (cai em `geral`); se o HTML inventar um\nassunto que o servidor não conhece, o validador o normaliza em vez de recusar.",
        "operationId": "assuntos_site_contato_assuntos_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": {
                    "items": {
                      "additionalProperties": {
                        "type": "string"
                      },
                      "type": "object"
                    },
                    "type": "array"
                  },
                  "type": "object",
                  "title": "Response Assuntos Site Contato Assuntos Get"
                }
              }
            }
          }
        }
      }
    },
    "/site/contato/estado": {
      "get": {
        "tags": [
          "site"
        ],
        "summary": "Estado",
        "description": "Diagnóstico honesto do canal, sem expor credencial.\n\nServe à verificação pós-deploy (regra canônica nº 6, item 5): responde se o ambiente\nestá de fato apto a ENVIAR, ou se está em sandbox — a diferença que, sem esta rota,\nsó apareceria quando um lead real se perdesse.",
        "operationId": "estado_site_contato_estado_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object",
                  "title": "Response Estado Site Contato Estado Get"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ContatoIn": {
        "properties": {
          "nome": {
            "type": "string",
            "maxLength": 120,
            "minLength": 2,
            "title": "Nome"
          },
          "email": {
            "type": "string",
            "format": "email",
            "title": "Email"
          },
          "assunto": {
            "type": "string",
            "title": "Assunto",
            "default": "comercial"
          },
          "mensagem": {
            "type": "string",
            "maxLength": 4000,
            "minLength": 10,
            "title": "Mensagem"
          },
          "empresa": {
            "type": "string",
            "maxLength": 140,
            "title": "Empresa",
            "default": ""
          },
          "telefone": {
            "type": "string",
            "maxLength": 40,
            "title": "Telefone",
            "default": ""
          },
          "site": {
            "type": "string",
            "maxLength": 200,
            "title": "Site",
            "default": ""
          }
        },
        "type": "object",
        "required": [
          "nome",
          "email",
          "mensagem"
        ],
        "title": "ContatoIn",
        "description": "Campos do formulário. Os limites são de sanidade, não de banco: nada aqui é\npersistido em coluna com largura — o destino é a trilha (JSONB) e o corpo do e-mail."
      },
      "ContatoOut": {
        "properties": {
          "protocolo": {
            "type": "string",
            "title": "Protocolo"
          },
          "destino": {
            "type": "string",
            "title": "Destino"
          },
          "mensagem": {
            "type": "string",
            "title": "Mensagem"
          }
        },
        "type": "object",
        "required": [
          "protocolo",
          "destino",
          "mensagem"
        ],
        "title": "ContatoOut"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "ManutencaoOut": {
        "properties": {
          "inicio": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Inicio"
          },
          "fim": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fim"
          },
          "mensagem": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mensagem"
          },
          "em_curso": {
            "type": "boolean",
            "title": "Em Curso",
            "default": false
          },
          "anunciada": {
            "type": "boolean",
            "title": "Anunciada",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "inicio",
          "fim",
          "mensagem"
        ],
        "title": "ManutencaoOut"
      },
      "ServicoOut": {
        "properties": {
          "nome": {
            "type": "string",
            "title": "Nome"
          },
          "ok": {
            "type": "boolean",
            "title": "Ok"
          },
          "latencia_ms": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Latencia Ms"
          },
          "modo": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Modo"
          }
        },
        "type": "object",
        "required": [
          "nome",
          "ok"
        ],
        "title": "ServicoOut"
      },
      "StatusOut": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status"
          },
          "ambiente": {
            "type": "string",
            "title": "Ambiente"
          },
          "versao": {
            "type": "string",
            "title": "Versao"
          },
          "servicos": {
            "items": {
              "$ref": "#/components/schemas/ServicoOut"
            },
            "type": "array",
            "title": "Servicos"
          },
          "manutencao": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ManutencaoOut"
              },
              {
                "type": "null"
              }
            ]
          },
          "verificado_em": {
            "type": "string",
            "format": "date-time",
            "title": "Verificado Em"
          }
        },
        "type": "object",
        "required": [
          "status",
          "ambiente",
          "versao",
          "servicos",
          "manutencao",
          "verificado_em"
        ],
        "title": "StatusOut"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "VersionOut": {
        "properties": {
          "versao": {
            "type": "string",
            "title": "Versao"
          },
          "commit": {
            "type": "string",
            "title": "Commit"
          },
          "ambiente": {
            "type": "string",
            "title": "Ambiente"
          },
          "build_em": {
            "type": "string",
            "title": "Build Em"
          },
          "schema_versao": {
            "type": "string",
            "title": "Schema Versao"
          }
        },
        "type": "object",
        "required": [
          "versao",
          "commit",
          "ambiente",
          "build_em",
          "schema_versao"
        ],
        "title": "VersionOut",
        "description": "Identidade da build. Campos vazios em dev (a imagem não é carimbada)."
      }
    }
  }
}
