{
  "openapi": "3.1.1",
  "info": {
    "title": "API do Festero",
    "description": "API somente de leitura dos dados de neg\u00F3cio de uma empresa no Festero: oportunidades de venda (CRM), visitas,\r\neventos, or\u00E7amentos e receb\u00EDveis. Os mesmos dados chegam a assistentes de IA pelo servidor MCP e, em tempo real,\r\npor webhooks.\r\n\r\nGuias de in\u00EDcio r\u00E1pido, autentica\u00E7\u00E3o, limites, pagina\u00E7\u00E3o, erros, webhooks e MCP: https://developers.festero.com.br",
    "contact": {
      "name": "Festero",
      "url": "https://developers.festero.com.br"
    },
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://platform.festero.com.br"
    }
  ],
  "paths": {
    "/v1/health": {
      "get": {
        "tags": [
          "Conta"
        ],
        "summary": "Verifica se a API est\u00E1 no ar.",
        "description": "N\u00E3o exige credencial e n\u00E3o traz dados da empresa. Responde \u0060status\u0060 com o valor \u0060ok\u0060 e a \u0060version\u0060 da API.",
        "responses": {
          "200": {
            "description": "Sucesso."
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "tags": [
          "Conta"
        ],
        "summary": "Identifica a credencial usada na chamada.",
        "description": "Devolve \u0060credentialId\u0060, \u0060workspaceId\u0060 (a empresa), os \u0060scopes\u0060 concedidos, o plano (\u0060tier\u0060) e o tipo de autentica\u00E7\u00E3o (\u0060authKind\u0060: \u0060jwt\u0060 para token de acesso, \u0060mcp_key\u0060 para chave MCP ou \u0060oauth\u0060 para um assistente conectado por login). Aceita qualquer credencial v\u00E1lida, sem escopo espec\u00EDfico, e n\u00E3o traz dados de neg\u00F3cio.",
        "responses": {
          "200": {
            "description": "Sucesso."
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/crm/opportunities": {
      "get": {
        "tags": [
          "CRM"
        ],
        "summary": "Lista as oportunidades de venda, da altera\u00E7\u00E3o mais antiga para a mais recente, com pagina\u00E7\u00E3o por cursor.",
        "description": "Exige o escopo \u0060crm:read\u0060. Oportunidades mescladas em outra n\u00E3o aparecem.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filtra pela situa\u00E7\u00E3o: \u0060open\u0060, \u0060won\u0060, \u0060lost\u0060, \u0060duplicate\u0060 ou \u0060notclient\u0060.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "stageId",
            "in": "query",
            "description": "S\u00F3 as oportunidades desta etapa do funil.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "S\u00F3 as oportunidades alteradas a partir deste instante (ISO 8601 com deslocamento).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Tamanho da p\u00E1gina, de 1 a 100 (padr\u00E3o 25).",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O \u0060nextCursor\u0060 da p\u00E1gina anterior.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "P\u00E1gina de uma lista paginada por cursor.",
                  "$ref": "#/components/schemas/PageOfOpportunityView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/crm/opportunities/{id}": {
      "get": {
        "tags": [
          "CRM"
        ],
        "summary": "Busca uma oportunidade de venda pelo identificador.",
        "description": "Exige o escopo \u0060crm:read\u0060. A resposta traz um \u0060ETag\u0060; envie-o em \u0060If-None-Match\u0060 para receber \u0060304\u0060 quando nada mudou.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Identificador da oportunidade.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Oportunidade de venda do CRM: um interessado no funil de vendas da empresa. Exige o escopo \u0060crm:read\u0060.\r\nN\u00E3o traz dado de contato do lead, anota\u00E7\u00F5es nem textos livres.",
                  "$ref": "#/components/schemas/OpportunityView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/crm/pipeline-stages": {
      "get": {
        "tags": [
          "CRM"
        ],
        "summary": "Lista as etapas do funil de vendas, na ordem do quadro.",
        "description": "Exige o escopo \u0060crm:read\u0060. A resposta usa o mesmo formato de p\u00E1gina das listas (\u0060data\u0060 e \u0060nextCursor\u0060), sempre com todas as etapas e \u0060nextCursor\u0060 nulo.",
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "P\u00E1gina de uma lista paginada por cursor.",
                  "$ref": "#/components/schemas/PageOfPipelineStageView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/events": {
      "get": {
        "tags": [
          "Eventos"
        ],
        "summary": "Lista os eventos (s\u00F3 os dados principais), da altera\u00E7\u00E3o mais antiga para a mais recente, com pagina\u00E7\u00E3o por cursor.",
        "description": "Exige o escopo \u0060events:read\u0060.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filtra pela situa\u00E7\u00E3o: \u0060draft\u0060, \u0060upcoming\u0060, \u0060confirmed\u0060, \u0060inprogress\u0060, \u0060completed\u0060 ou \u0060cancelled\u0060.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "eventDateFrom",
            "in": "query",
            "description": "Data do evento a partir da qual listar (\u0060yyyy-MM-dd\u0060, inclusiva).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "eventDateTo",
            "in": "query",
            "description": "Data do evento at\u00E9 a qual listar (\u0060yyyy-MM-dd\u0060, inclusiva).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "S\u00F3 os eventos alterados a partir deste instante (ISO 8601 com deslocamento).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Tamanho da p\u00E1gina, de 1 a 100 (padr\u00E3o 25).",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O \u0060nextCursor\u0060 da p\u00E1gina anterior.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "P\u00E1gina de uma lista paginada por cursor.",
                  "$ref": "#/components/schemas/PageOfEventView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/events/{id}": {
      "get": {
        "tags": [
          "Eventos"
        ],
        "summary": "Busca um evento pelo identificador (s\u00F3 os dados principais).",
        "description": "Exige o escopo \u0060events:read\u0060. A resposta traz um \u0060ETag\u0060; envie-o em \u0060If-None-Match\u0060 para receber \u0060304\u0060 quando nada mudou.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Identificador do evento.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Evento da empresa, s\u00F3 com os dados principais: identidade, data, hor\u00E1rio, situa\u00E7\u00E3o, tipo, cliente e valor total,\r\nmais convidados previstos e cidade. Exige o escopo \u0060events:read\u0060. N\u00E3o traz endere\u00E7o completo, valores de custo,\r\nlista de convidados, respostas de formul\u00E1rios nem textos livres.",
                  "$ref": "#/components/schemas/EventView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/finance/receivables": {
      "get": {
        "tags": [
          "Financeiro"
        ],
        "summary": "Lista os receb\u00EDveis (parcelas), da altera\u00E7\u00E3o mais antiga para a mais recente, com pagina\u00E7\u00E3o por cursor.",
        "description": "Exige o escopo \u0060finance:read\u0060. Para totais de um per\u00EDodo, prefira \u0060GET /v1/finance/sales-summary\u0060.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filtra pela situa\u00E7\u00E3o: \u0060pending\u0060, \u0060partiallypaid\u0060, \u0060paid\u0060, \u0060overdue\u0060 ou \u0060cancelled\u0060.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dueFrom",
            "in": "query",
            "description": "Vencimento a partir do qual listar (\u0060yyyy-MM-dd\u0060, inclusivo).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dueTo",
            "in": "query",
            "description": "Vencimento at\u00E9 o qual listar (\u0060yyyy-MM-dd\u0060, inclusivo).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "eventId",
            "in": "query",
            "description": "S\u00F3 os receb\u00EDveis deste evento.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "S\u00F3 os receb\u00EDveis alterados a partir deste instante (ISO 8601 com deslocamento).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Tamanho da p\u00E1gina, de 1 a 100 (padr\u00E3o 25).",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O \u0060nextCursor\u0060 da p\u00E1gina anterior.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "P\u00E1gina de uma lista paginada por cursor.",
                  "$ref": "#/components/schemas/PageOfReceivableView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/finance/receivables/{id}": {
      "get": {
        "tags": [
          "Financeiro"
        ],
        "summary": "Busca um receb\u00EDvel pelo identificador.",
        "description": "Exige o escopo \u0060finance:read\u0060. A resposta traz um \u0060ETag\u0060; envie-o em \u0060If-None-Match\u0060 para receber \u0060304\u0060 quando nada mudou.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Identificador do receb\u00EDvel.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Receb\u00EDvel (parcela) do financeiro: um valor que a empresa tem a receber de um cliente. Exige o escopo\r\n\u0060finance:read\u0060. N\u00E3o traz custo, margem, comprovantes nem dados de cobran\u00E7a.",
                  "$ref": "#/components/schemas/ReceivableView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/finance/sales-summary": {
      "get": {
        "tags": [
          "Financeiro"
        ],
        "summary": "Totais de vendas e de receb\u00EDveis de um per\u00EDodo, pela data do evento. Mesmos n\u00FAmeros do relat\u00F3rio de Vendas do Festero.",
        "description": "Exige o escopo \u0060finance:read\u0060. Uma chamada no lugar de percorrer todos os eventos e receb\u00EDveis. Os dois par\u00E2metros s\u00E3o obrigat\u00F3rios; \u0060to\u0060 n\u00E3o pode ser anterior a \u0060from\u0060 nem passar de 366 dias depois dele.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "description": "Primeira data do per\u00EDodo (\u0060yyyy-MM-dd\u0060, inclusiva). Vale para a data do evento e para o vencimento dos receb\u00EDveis.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "\u00DAltima data do per\u00EDodo (\u0060yyyy-MM-dd\u0060, inclusiva). No m\u00E1ximo 366 dias depois de \u0060from\u0060.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Resumo de vendas de um per\u00EDodo, com os mesmos n\u00FAmeros da tela Relat\u00F3rios, Vendas do Festero. Exige o escopo\r\n\u0060finance:read\u0060. Uma \u00FAnica chamada substitui percorrer todos os eventos e receb\u00EDveis.",
                  "$ref": "#/components/schemas/SalesSummaryView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/quotes": {
      "get": {
        "tags": [
          "Or\u00E7amentos"
        ],
        "summary": "Lista os or\u00E7amentos, da altera\u00E7\u00E3o mais antiga para a mais recente, com pagina\u00E7\u00E3o por cursor.",
        "description": "Exige o escopo \u0060quotes:read\u0060. A lista traz o resumo de cada or\u00E7amento; as op\u00E7\u00F5es e os itens v\u00EAm na busca por identificador.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filtra pela situa\u00E7\u00E3o: \u0060draft\u0060, \u0060sent\u0060, \u0060approved\u0060, \u0060rejected\u0060, \u0060expired\u0060 ou \u0060cancelled\u0060.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "eventDateFrom",
            "in": "query",
            "description": "Data do evento a partir da qual listar (\u0060yyyy-MM-dd\u0060, inclusiva).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "eventDateTo",
            "in": "query",
            "description": "Data do evento at\u00E9 a qual listar (\u0060yyyy-MM-dd\u0060, inclusiva).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "S\u00F3 os or\u00E7amentos alterados a partir deste instante (ISO 8601 com deslocamento).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Tamanho da p\u00E1gina, de 1 a 100 (padr\u00E3o 25).",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O \u0060nextCursor\u0060 da p\u00E1gina anterior.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "P\u00E1gina de uma lista paginada por cursor.",
                  "$ref": "#/components/schemas/PageOfQuoteSummary"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/quotes/{id}": {
      "get": {
        "tags": [
          "Or\u00E7amentos"
        ],
        "summary": "Busca um or\u00E7amento pelo identificador, com as op\u00E7\u00F5es e as linhas (itens).",
        "description": "Exige o escopo \u0060quotes:read\u0060. A resposta traz um \u0060ETag\u0060; envie-o em \u0060If-None-Match\u0060 para receber \u0060304\u0060 quando nada mudou.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Identificador do or\u00E7amento.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Or\u00E7amento completo: os mesmos campos do resumo, mais as op\u00E7\u00F5es e as linhas (itens). Exige o escopo \u0060quotes:read\u0060.",
                  "$ref": "#/components/schemas/QuoteDetail"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/visits": {
      "get": {
        "tags": [
          "Visitas"
        ],
        "summary": "Lista as visitas, da altera\u00E7\u00E3o mais antiga para a mais recente, com pagina\u00E7\u00E3o por cursor.",
        "description": "Exige o escopo \u0060visits:read\u0060.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filtra pela situa\u00E7\u00E3o: \u0060requested\u0060, \u0060scheduled\u0060, \u0060completed\u0060, \u0060noshow\u0060 ou \u0060cancelled\u0060.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "startFrom",
            "in": "query",
            "description": "In\u00EDcio agendado a partir do qual listar (\u0060yyyy-MM-dd\u0060, inclusiva, hor\u00E1rio de Bras\u00EDlia).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "startTo",
            "in": "query",
            "description": "In\u00EDcio agendado at\u00E9 o qual listar (\u0060yyyy-MM-dd\u0060, inclusiva, hor\u00E1rio de Bras\u00EDlia).",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "description": "S\u00F3 as visitas alteradas a partir deste instante (ISO 8601 com deslocamento).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Tamanho da p\u00E1gina, de 1 a 100 (padr\u00E3o 25).",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O \u0060nextCursor\u0060 da p\u00E1gina anterior.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "P\u00E1gina de uma lista paginada por cursor.",
                  "$ref": "#/components/schemas/PageOfVisitView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/visits/{id}": {
      "get": {
        "tags": [
          "Visitas"
        ],
        "summary": "Busca uma visita pelo identificador.",
        "description": "Exige o escopo \u0060visits:read\u0060. A resposta traz um \u0060ETag\u0060; envie-o em \u0060If-None-Match\u0060 para receber \u0060304\u0060 quando nada mudou.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Identificador da visita.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Visita de um cliente interessado ao espa\u00E7o da empresa. Exige o escopo \u0060visits:read\u0060. Os hor\u00E1rios v\u00EAm em ISO 8601\r\ncom o deslocamento de Bras\u00EDlia. N\u00E3o traz telefone, e-mail, nome de contato, link de reuni\u00E3o nem anota\u00E7\u00F5es.",
                  "$ref": "#/components/schemas/VisitView"
                }
              }
            }
          },
          "4XX": {
            "description": "Erro no formato Problem Details (\u0060application/problem\u002Bjson\u0060) com um \u0060code\u0060 est\u00E1vel, como \u0060validation_failed\u0060, \u0060token_invalid\u0060, \u0060credential_revoked\u0060, \u0060scope_missing\u0060, \u0060not_found\u0060 ou \u0060rate_limited\u0060. Todos os c\u00F3digos: https://developers.festero.com.br/errors",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          },
          "5XX": {
            "description": "Erro do servidor ou do gateway (\u0060internal_error\u0060, \u0060gateway_error\u0060), com um \u0060requestId\u0060 para o suporte.",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060.",
                  "$ref": "#/components/schemas/ProblemDoc"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "EventView": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador do evento.",
            "format": "uuid"
          },
          "title": {
            "type": [
              "null",
              "string"
            ],
            "description": "T\u00EDtulo do evento (o nome de exibi\u00E7\u00E3o, quando houver). Trechos que parecem telefone, e-mail ou documento aparecem como \u0060[oculto]\u0060."
          },
          "status": {
            "type": [
              "null",
              "string"
            ],
            "description": "Situa\u00E7\u00E3o: \u0060draft\u0060, \u0060upcoming\u0060, \u0060confirmed\u0060, \u0060inprogress\u0060, \u0060completed\u0060 ou \u0060cancelled\u0060."
          },
          "kind": {
            "type": [
              "null",
              "string"
            ],
            "description": "Natureza do evento: \u0060conventional\u0060, \u0060rental\u0060 ou \u0060show\u0060."
          },
          "eventType": {
            "description": "Tipo de evento cadastrado pela empresa.",
            "$ref": "#/components/schemas/Reference"
          },
          "client": {
            "description": "Cliente do evento.",
            "$ref": "#/components/schemas/Reference"
          },
          "eventDate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Data do evento, no formato \u0060yyyy-MM-dd\u0060."
          },
          "eventTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Hor\u00E1rio do evento, como cadastrado no Festero."
          },
          "durationHours": {
            "type": [
              "null",
              "number"
            ],
            "description": "Dura\u00E7\u00E3o do evento, em horas.",
            "format": "double"
          },
          "guestCount": {
            "type": [
              "null",
              "integer"
            ],
            "description": "N\u00FAmero de convidados previstos.",
            "format": "int32"
          },
          "city": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cidade do evento."
          },
          "state": {
            "type": [
              "null",
              "string"
            ],
            "description": "Estado do evento."
          },
          "isRental": {
            "type": "boolean",
            "description": "Indica que o evento \u00E9 uma loca\u00E7\u00E3o."
          },
          "quoteId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Or\u00E7amento vinculado ao evento, quando houver.",
            "format": "uuid"
          },
          "totalAmount": {
            "description": "Valor total do evento.",
            "$ref": "#/components/schemas/Money"
          },
          "discount": {
            "description": "Desconto aplicado ao evento.",
            "$ref": "#/components/schemas/Money"
          },
          "travelFee": {
            "description": "Taxa de deslocamento do evento.",
            "$ref": "#/components/schemas/Money"
          },
          "contractedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da contrata\u00E7\u00E3o (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "createdAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da cria\u00E7\u00E3o (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "updatedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da \u00FAltima altera\u00E7\u00E3o (ISO 8601 com deslocamento). Nulo se nunca foi alterado.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Evento da empresa, s\u00F3 com os dados principais: identidade, data, hor\u00E1rio, situa\u00E7\u00E3o, tipo, cliente e valor total,\r\nmais convidados previstos e cidade. Exige o escopo \u0060events:read\u0060. N\u00E3o traz endere\u00E7o completo, valores de custo,\r\nlista de convidados, respostas de formul\u00E1rios nem textos livres."
      },
      "FieldError": {
        "type": "object",
        "properties": {
          "field": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nome do par\u00E2metro inv\u00E1lido."
          },
          "message": {
            "type": [
              "null",
              "string"
            ],
            "description": "O que est\u00E1 errado, em ingl\u00EAs."
          }
        },
        "additionalProperties": false,
        "description": "Campo inv\u00E1lido de uma requisi\u00E7\u00E3o, listado em \u0060errors\u0060 no erro \u0060validation_failed\u0060."
      },
      "Money": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Valor decimal, com duas casas.",
            "format": "double"
          },
          "currency": {
            "type": [
              "null",
              "string"
            ],
            "description": "C\u00F3digo da moeda. Hoje \u00E9 sempre \u0060BRL\u0060."
          }
        },
        "additionalProperties": false,
        "description": "Valor em dinheiro com a moeda expl\u00EDcita. \u00C9 sempre o pre\u00E7o ao cliente, nunca custo ou margem."
      },
      "OpportunityView": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador da oportunidade.",
            "format": "uuid"
          },
          "title": {
            "type": [
              "null",
              "string"
            ],
            "description": "T\u00EDtulo da oportunidade. Trechos que parecem telefone, e-mail ou documento aparecem como \u0060[oculto]\u0060."
          },
          "status": {
            "type": [
              "null",
              "string"
            ],
            "description": "Situa\u00E7\u00E3o: \u0060open\u0060, \u0060won\u0060, \u0060lost\u0060, \u0060duplicate\u0060 ou \u0060notclient\u0060."
          },
          "stage": {
            "description": "Etapa atual no funil.",
            "$ref": "#/components/schemas/Reference"
          },
          "client": {
            "description": "Cliente vinculado, quando houver.",
            "$ref": "#/components/schemas/Reference"
          },
          "quoteId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Or\u00E7amento vinculado, quando houver.",
            "format": "uuid"
          },
          "eventId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Evento vinculado, quando houver.",
            "format": "uuid"
          },
          "estimatedValue": {
            "description": "Valor estimado da venda.",
            "$ref": "#/components/schemas/Money"
          },
          "expectedEventDate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Data do evento pedida pelo cliente, no formato \u0060yyyy-MM-dd\u0060. Na tela do Festero, \u0022Data do evento\u0022."
          },
          "eventTypeName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nome do tipo de evento pretendido."
          },
          "estimatedGuests": {
            "type": [
              "null",
              "integer"
            ],
            "description": "N\u00FAmero estimado de convidados.",
            "format": "int32"
          },
          "source": {
            "type": [
              "null",
              "string"
            ],
            "description": "Origem da oportunidade (canal de capta\u00E7\u00E3o), em min\u00FAsculas."
          },
          "closeReason": {
            "type": [
              "null",
              "string"
            ],
            "description": "C\u00F3digo do motivo do fechamento, quando a oportunidade foi encerrada. Nunca traz texto livre."
          },
          "closedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante do fechamento (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "lastContactAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante do \u00FAltimo contato (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "nextFollowUpAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante do pr\u00F3ximo retorno agendado (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "createdAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da cria\u00E7\u00E3o (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "updatedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da \u00FAltima altera\u00E7\u00E3o (ISO 8601 com deslocamento). Nulo se nunca foi alterada.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Oportunidade de venda do CRM: um interessado no funil de vendas da empresa. Exige o escopo \u0060crm:read\u0060.\r\nN\u00E3o traz dado de contato do lead, anota\u00E7\u00F5es nem textos livres."
      },
      "PageOfEventView": {
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "description": "Evento da empresa, s\u00F3 com os dados principais: identidade, data, hor\u00E1rio, situa\u00E7\u00E3o, tipo, cliente e valor total,\r\nmais convidados previstos e cidade. Exige o escopo \u0060events:read\u0060. N\u00E3o traz endere\u00E7o completo, valores de custo,\r\nlista de convidados, respostas de formul\u00E1rios nem textos livres.",
              "$ref": "#/components/schemas/EventView"
            },
            "description": "Itens da p\u00E1gina."
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cursor para pedir a pr\u00F3xima p\u00E1gina, no par\u00E2metro \u0060cursor\u0060. Nulo na \u00FAltima p\u00E1gina."
          }
        },
        "additionalProperties": false,
        "description": "P\u00E1gina de uma lista paginada por cursor."
      },
      "PageOfOpportunityView": {
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "description": "Oportunidade de venda do CRM: um interessado no funil de vendas da empresa. Exige o escopo \u0060crm:read\u0060.\r\nN\u00E3o traz dado de contato do lead, anota\u00E7\u00F5es nem textos livres.",
              "$ref": "#/components/schemas/OpportunityView"
            },
            "description": "Itens da p\u00E1gina."
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cursor para pedir a pr\u00F3xima p\u00E1gina, no par\u00E2metro \u0060cursor\u0060. Nulo na \u00FAltima p\u00E1gina."
          }
        },
        "additionalProperties": false,
        "description": "P\u00E1gina de uma lista paginada por cursor."
      },
      "PageOfPipelineStageView": {
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "description": "Etapa do funil de vendas. A lista vem na mesma ordem do quadro do CRM no Festero.",
              "$ref": "#/components/schemas/PipelineStageView"
            },
            "description": "Itens da p\u00E1gina."
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cursor para pedir a pr\u00F3xima p\u00E1gina, no par\u00E2metro \u0060cursor\u0060. Nulo na \u00FAltima p\u00E1gina."
          }
        },
        "additionalProperties": false,
        "description": "P\u00E1gina de uma lista paginada por cursor."
      },
      "PageOfQuoteSummary": {
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "description": "Or\u00E7amento enviado a um cliente, em formato resumido (sem op\u00E7\u00F5es nem itens). Exige o escopo \u0060quotes:read\u0060.\r\nOs valores s\u00E3o o pre\u00E7o ao cliente. N\u00E3o traz anota\u00E7\u00F5es, endere\u00E7o completo nem custos.",
              "$ref": "#/components/schemas/QuoteSummary"
            },
            "description": "Itens da p\u00E1gina."
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cursor para pedir a pr\u00F3xima p\u00E1gina, no par\u00E2metro \u0060cursor\u0060. Nulo na \u00FAltima p\u00E1gina."
          }
        },
        "additionalProperties": false,
        "description": "P\u00E1gina de uma lista paginada por cursor."
      },
      "PageOfReceivableView": {
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "description": "Receb\u00EDvel (parcela) do financeiro: um valor que a empresa tem a receber de um cliente. Exige o escopo\r\n\u0060finance:read\u0060. N\u00E3o traz custo, margem, comprovantes nem dados de cobran\u00E7a.",
              "$ref": "#/components/schemas/ReceivableView"
            },
            "description": "Itens da p\u00E1gina."
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cursor para pedir a pr\u00F3xima p\u00E1gina, no par\u00E2metro \u0060cursor\u0060. Nulo na \u00FAltima p\u00E1gina."
          }
        },
        "additionalProperties": false,
        "description": "P\u00E1gina de uma lista paginada por cursor."
      },
      "PageOfVisitView": {
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "description": "Visita de um cliente interessado ao espa\u00E7o da empresa. Exige o escopo \u0060visits:read\u0060. Os hor\u00E1rios v\u00EAm em ISO 8601\r\ncom o deslocamento de Bras\u00EDlia. N\u00E3o traz telefone, e-mail, nome de contato, link de reuni\u00E3o nem anota\u00E7\u00F5es.",
              "$ref": "#/components/schemas/VisitView"
            },
            "description": "Itens da p\u00E1gina."
          },
          "nextCursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cursor para pedir a pr\u00F3xima p\u00E1gina, no par\u00E2metro \u0060cursor\u0060. Nulo na \u00FAltima p\u00E1gina."
          }
        },
        "additionalProperties": false,
        "description": "P\u00E1gina de uma lista paginada por cursor."
      },
      "PipelineStageView": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador da etapa.",
            "format": "uuid"
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nome da etapa."
          },
          "color": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cor da etapa no quadro, em hexadecimal."
          },
          "displayOrder": {
            "type": "integer",
            "description": "Posi\u00E7\u00E3o da etapa no funil.",
            "format": "int32"
          },
          "isDefault": {
            "type": "boolean",
            "description": "Indica a etapa padr\u00E3o do funil."
          },
          "isClosedWon": {
            "type": "boolean",
            "description": "Indica que a etapa significa venda ganha."
          },
          "isClosedLost": {
            "type": "boolean",
            "description": "Indica que a etapa significa venda perdida."
          },
          "isVisitStage": {
            "type": "boolean",
            "description": "Indica a etapa para onde vai a oportunidade quando uma visita \u00E9 marcada."
          }
        },
        "additionalProperties": false,
        "description": "Etapa do funil de vendas. A lista vem na mesma ordem do quadro do CRM no Festero."
      },
      "ProblemDoc": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ],
            "description": "Endere\u00E7o da documenta\u00E7\u00E3o do c\u00F3digo do erro, por exemplo \u0060https://developers.festero.com.br/errors#scope_missing\u0060."
          },
          "title": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nome curto do status HTTP, em ingl\u00EAs."
          },
          "status": {
            "type": "integer",
            "description": "Status HTTP da resposta.",
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ],
            "description": "Explica\u00E7\u00E3o em ingl\u00EAs, para o registro. O texto pode mudar sem aviso: decida pelo \u0060code\u0060."
          },
          "code": {
            "type": [
              "null",
              "string"
            ],
            "description": "C\u00F3digo est\u00E1vel do erro. \u00C9 ele que o seu c\u00F3digo deve tratar."
          },
          "requestId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identificador da chamada. Informe-o ao suporte."
          },
          "errors": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "description": "Campo inv\u00E1lido de uma requisi\u00E7\u00E3o, listado em \u0060errors\u0060 no erro \u0060validation_failed\u0060.",
              "$ref": "#/components/schemas/FieldError"
            },
            "description": "S\u00F3 no erro \u0060validation_failed\u0060: os campos inv\u00E1lidos."
          }
        },
        "additionalProperties": false,
        "description": "Erro da API no formato Problem Details (RFC 9457), com o tipo de conte\u00FAdo \u0060application/problem\u002Bjson\u0060."
      },
      "QuoteDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador do or\u00E7amento.",
            "format": "uuid"
          },
          "title": {
            "type": [
              "null",
              "string"
            ],
            "description": "T\u00EDtulo do or\u00E7amento (o nome de exibi\u00E7\u00E3o, quando houver). Trechos que parecem telefone, e-mail ou documento aparecem como \u0060[oculto]\u0060."
          },
          "status": {
            "type": [
              "null",
              "string"
            ],
            "description": "Situa\u00E7\u00E3o: \u0060draft\u0060, \u0060sent\u0060, \u0060approved\u0060, \u0060rejected\u0060, \u0060expired\u0060 ou \u0060cancelled\u0060."
          },
          "client": {
            "description": "Cliente do or\u00E7amento.",
            "$ref": "#/components/schemas/Reference"
          },
          "eventId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Evento vinculado ao or\u00E7amento, quando houver.",
            "format": "uuid"
          },
          "eventDate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Data do evento, no formato \u0060yyyy-MM-dd\u0060."
          },
          "eventTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Hor\u00E1rio do evento, como cadastrado no Festero."
          },
          "guestCount": {
            "type": [
              "null",
              "integer"
            ],
            "description": "N\u00FAmero de convidados.",
            "format": "int32"
          },
          "eventType": {
            "description": "Tipo de evento cadastrado pela empresa.",
            "$ref": "#/components/schemas/Reference"
          },
          "packageName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nome do pacote do or\u00E7amento."
          },
          "isRental": {
            "type": "boolean",
            "description": "Indica que o or\u00E7amento \u00E9 de uma loca\u00E7\u00E3o."
          },
          "city": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cidade do evento."
          },
          "state": {
            "type": [
              "null",
              "string"
            ],
            "description": "Estado do evento."
          },
          "subtotal": {
            "description": "Soma dos itens, antes do desconto.",
            "$ref": "#/components/schemas/Money"
          },
          "discount": {
            "description": "Desconto do or\u00E7amento.",
            "$ref": "#/components/schemas/Money"
          },
          "travelFee": {
            "description": "Taxa de deslocamento, quando houver.",
            "$ref": "#/components/schemas/Money"
          },
          "total": {
            "description": "Valor total do or\u00E7amento. \u00C9 o valor oficial: use-o em vez de somar as linhas.",
            "$ref": "#/components/schemas/Money"
          },
          "validUntil": {
            "type": [
              "null",
              "string"
            ],
            "description": "Data at\u00E9 a qual o or\u00E7amento vale, no formato \u0060yyyy-MM-dd\u0060."
          },
          "sentAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante do envio ao cliente (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "approvedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da aprova\u00E7\u00E3o (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "createdAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da cria\u00E7\u00E3o (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "updatedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da \u00FAltima altera\u00E7\u00E3o (ISO 8601 com deslocamento). Nulo se nunca foi alterado.",
            "format": "date-time"
          },
          "options": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "description": "Op\u00E7\u00E3o de um or\u00E7amento com v\u00E1rias propostas. Num or\u00E7amento sem op\u00E7\u00F5es, a lista de op\u00E7\u00F5es vem vazia.",
              "$ref": "#/components/schemas/QuoteOptionView"
            },
            "description": "Op\u00E7\u00F5es do or\u00E7amento. Vem vazia quando o or\u00E7amento n\u00E3o tem v\u00E1rias propostas."
          },
          "items": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "description": "Linha (item) do or\u00E7amento. \u0060unitPrice\u0060 \u00E9 o pre\u00E7o efetivo ao cliente e \u0060total\u0060 segue a mesma regra da tela do\r\nFestero: itens por convidado multiplicam pelos convidados, itens sem quantidade valem o pre\u00E7o cheio.",
              "$ref": "#/components/schemas/QuoteItemView"
            },
            "description": "Linhas (itens) do or\u00E7amento."
          }
        },
        "additionalProperties": false,
        "description": "Or\u00E7amento completo: os mesmos campos do resumo, mais as op\u00E7\u00F5es e as linhas (itens). Exige o escopo \u0060quotes:read\u0060."
      },
      "QuoteItemView": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador da linha.",
            "format": "uuid"
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nome do item."
          },
          "category": {
            "type": [
              "null",
              "string"
            ],
            "description": "Categoria do item."
          },
          "quantity": {
            "type": "number",
            "description": "Quantidade.",
            "format": "double"
          },
          "unit": {
            "type": [
              "null",
              "string"
            ],
            "description": "Unidade de venda, em min\u00FAsculas. \u0060perguest\u0060 multiplica pelo n\u00FAmero de convidados; \u0060noquantity\u0060 e \u0060unlimited\u0060 valem o pre\u00E7o cheio, sem quantidade."
          },
          "unitPrice": {
            "description": "Pre\u00E7o unit\u00E1rio efetivo ao cliente.",
            "$ref": "#/components/schemas/Money"
          },
          "total": {
            "description": "Total da linha.",
            "$ref": "#/components/schemas/Money"
          },
          "isIncluded": {
            "type": "boolean",
            "description": "Falso indica item adicional, cobrado \u00E0 parte e fora do rateio das parcelas."
          },
          "isFromPackage": {
            "type": "boolean",
            "description": "Indica que a linha representa um pacote do cat\u00E1logo."
          },
          "optionId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Op\u00E7\u00E3o a que a linha pertence. Nulo significa que vale para todas as op\u00E7\u00F5es.",
            "format": "uuid"
          }
        },
        "additionalProperties": false,
        "description": "Linha (item) do or\u00E7amento. \u0060unitPrice\u0060 \u00E9 o pre\u00E7o efetivo ao cliente e \u0060total\u0060 segue a mesma regra da tela do\r\nFestero: itens por convidado multiplicam pelos convidados, itens sem quantidade valem o pre\u00E7o cheio."
      },
      "QuoteOptionView": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador da op\u00E7\u00E3o.",
            "format": "uuid"
          },
          "label": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nome da op\u00E7\u00E3o."
          },
          "isDefault": {
            "type": "boolean",
            "description": "Indica a op\u00E7\u00E3o padr\u00E3o: enquanto o cliente n\u00E3o escolhe, o total do or\u00E7amento segue ela."
          },
          "isChosen": {
            "type": "boolean",
            "description": "Indica a op\u00E7\u00E3o que o cliente (ou a empresa, em nome dele) escolheu. No m\u00E1ximo uma por or\u00E7amento."
          },
          "discount": {
            "description": "Desconto desta op\u00E7\u00E3o. Com op\u00E7\u00F5es, cada uma desconta o seu valor.",
            "$ref": "#/components/schemas/Money"
          }
        },
        "additionalProperties": false,
        "description": "Op\u00E7\u00E3o de um or\u00E7amento com v\u00E1rias propostas. Num or\u00E7amento sem op\u00E7\u00F5es, a lista de op\u00E7\u00F5es vem vazia."
      },
      "QuoteSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador do or\u00E7amento.",
            "format": "uuid"
          },
          "title": {
            "type": [
              "null",
              "string"
            ],
            "description": "T\u00EDtulo do or\u00E7amento (o nome de exibi\u00E7\u00E3o, quando houver). Trechos que parecem telefone, e-mail ou documento aparecem como \u0060[oculto]\u0060."
          },
          "status": {
            "type": [
              "null",
              "string"
            ],
            "description": "Situa\u00E7\u00E3o: \u0060draft\u0060, \u0060sent\u0060, \u0060approved\u0060, \u0060rejected\u0060, \u0060expired\u0060 ou \u0060cancelled\u0060."
          },
          "client": {
            "description": "Cliente do or\u00E7amento.",
            "$ref": "#/components/schemas/Reference"
          },
          "eventId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Evento vinculado ao or\u00E7amento, quando houver.",
            "format": "uuid"
          },
          "eventDate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Data do evento, no formato \u0060yyyy-MM-dd\u0060."
          },
          "eventTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Hor\u00E1rio do evento, como cadastrado no Festero."
          },
          "guestCount": {
            "type": [
              "null",
              "integer"
            ],
            "description": "N\u00FAmero de convidados.",
            "format": "int32"
          },
          "eventType": {
            "description": "Tipo de evento cadastrado pela empresa.",
            "$ref": "#/components/schemas/Reference"
          },
          "packageName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nome do pacote do or\u00E7amento."
          },
          "isRental": {
            "type": "boolean",
            "description": "Indica que o or\u00E7amento \u00E9 de uma loca\u00E7\u00E3o."
          },
          "city": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cidade do evento."
          },
          "state": {
            "type": [
              "null",
              "string"
            ],
            "description": "Estado do evento."
          },
          "subtotal": {
            "description": "Soma dos itens, antes do desconto.",
            "$ref": "#/components/schemas/Money"
          },
          "discount": {
            "description": "Desconto do or\u00E7amento.",
            "$ref": "#/components/schemas/Money"
          },
          "travelFee": {
            "description": "Taxa de deslocamento, quando houver.",
            "$ref": "#/components/schemas/Money"
          },
          "total": {
            "description": "Valor total do or\u00E7amento. \u00C9 o valor oficial: use-o em vez de somar as linhas.",
            "$ref": "#/components/schemas/Money"
          },
          "validUntil": {
            "type": [
              "null",
              "string"
            ],
            "description": "Data at\u00E9 a qual o or\u00E7amento vale, no formato \u0060yyyy-MM-dd\u0060."
          },
          "sentAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante do envio ao cliente (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "approvedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da aprova\u00E7\u00E3o (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "createdAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da cria\u00E7\u00E3o (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "updatedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da \u00FAltima altera\u00E7\u00E3o (ISO 8601 com deslocamento). Nulo se nunca foi alterado.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Or\u00E7amento enviado a um cliente, em formato resumido (sem op\u00E7\u00F5es nem itens). Exige o escopo \u0060quotes:read\u0060.\r\nOs valores s\u00E3o o pre\u00E7o ao cliente. N\u00E3o traz anota\u00E7\u00F5es, endere\u00E7o completo nem custos."
      },
      "ReceivableView": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador do receb\u00EDvel.",
            "format": "uuid"
          },
          "status": {
            "type": [
              "null",
              "string"
            ],
            "description": "Situa\u00E7\u00E3o: \u0060pending\u0060, \u0060partiallypaid\u0060, \u0060paid\u0060, \u0060overdue\u0060 ou \u0060cancelled\u0060."
          },
          "kind": {
            "type": [
              "null",
              "string"
            ],
            "description": "Tipo do receb\u00EDvel, em min\u00FAsculas: \u0060regular\u0060, \u0060additionalitem\u0060 (item adicional, fora do rateio das parcelas), \u0060travelfee\u0060 (taxa de deslocamento) ou \u0060travelfeeadjustment\u0060 (ajuste da taxa de deslocamento)."
          },
          "description": {
            "type": [
              "null",
              "string"
            ],
            "description": "Descri\u00E7\u00E3o do receb\u00EDvel. Trechos que parecem telefone, e-mail ou documento aparecem como \u0060[oculto]\u0060."
          },
          "amount": {
            "description": "Valor cobrado do cliente, j\u00E1 com a taxa de cart\u00E3o repassada, quando houver.",
            "$ref": "#/components/schemas/Money"
          },
          "receivedAmount": {
            "description": "Valor j\u00E1 recebido.",
            "$ref": "#/components/schemas/Money"
          },
          "dueDate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Data de vencimento, no formato \u0060yyyy-MM-dd\u0060."
          },
          "paidDate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Data do pagamento, no formato \u0060yyyy-MM-dd\u0060. Nulo enquanto n\u00E3o houver pagamento."
          },
          "eventId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Evento a que o receb\u00EDvel pertence, quando houver.",
            "format": "uuid"
          },
          "client": {
            "description": "Cliente do receb\u00EDvel.",
            "$ref": "#/components/schemas/Reference"
          },
          "category": {
            "description": "Categoria financeira do receb\u00EDvel.",
            "$ref": "#/components/schemas/Reference"
          },
          "createdAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da cria\u00E7\u00E3o (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "updatedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da \u00FAltima altera\u00E7\u00E3o (ISO 8601 com deslocamento). Nulo se nunca foi alterado.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Receb\u00EDvel (parcela) do financeiro: um valor que a empresa tem a receber de um cliente. Exige o escopo\r\n\u0060finance:read\u0060. N\u00E3o traz custo, margem, comprovantes nem dados de cobran\u00E7a."
      },
      "ReceivablesSummary": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Quantidade de receb\u00EDveis com vencimento no per\u00EDodo.",
            "format": "int32"
          },
          "amount": {
            "description": "Soma dos valores cobrados.",
            "$ref": "#/components/schemas/Money"
          },
          "received": {
            "description": "Soma do que j\u00E1 foi recebido.",
            "$ref": "#/components/schemas/Money"
          },
          "outstanding": {
            "description": "Valor em aberto: \u0060amount\u0060 menos \u0060received\u0060.",
            "$ref": "#/components/schemas/Money"
          },
          "overdueCount": {
            "type": "integer",
            "description": "Quantidade de receb\u00EDveis vencidos.",
            "format": "int32"
          },
          "overdueAmount": {
            "description": "Valor ainda em aberto dos receb\u00EDveis vencidos (o valor cobrado menos o que j\u00E1 foi recebido).",
            "$ref": "#/components/schemas/Money"
          }
        },
        "additionalProperties": false,
        "description": "Receb\u00EDveis n\u00E3o cancelados com vencimento no per\u00EDodo. Os campos \u0060overdue\u0060 consideram os que est\u00E3o vencidos hoje."
      },
      "Reference": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador do recurso referenciado.",
            "format": "uuid"
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nome leg\u00EDvel. Trechos que parecem telefone, e-mail ou documento aparecem como \u0060[oculto]\u0060."
          }
        },
        "additionalProperties": false,
        "description": "Refer\u00EAncia curta a outro recurso: s\u00F3 o identificador e o nome."
      },
      "SalesSummaryView": {
        "type": "object",
        "properties": {
          "from": {
            "type": [
              "null",
              "string"
            ],
            "description": "Primeira data do per\u00EDodo, no formato \u0060yyyy-MM-dd\u0060."
          },
          "to": {
            "type": [
              "null",
              "string"
            ],
            "description": "\u00DAltima data do per\u00EDodo, no formato \u0060yyyy-MM-dd\u0060."
          },
          "basis": {
            "type": [
              "null",
              "string"
            ],
            "description": "Base do c\u00E1lculo. Hoje \u00E9 sempre \u0060event_date\u0060: os eventos entram pela data do evento."
          },
          "soldEvents": {
            "description": "Eventos vendidos no per\u00EDodo (situa\u00E7\u00F5es Agendado e Realizado).",
            "$ref": "#/components/schemas/SoldEventsSummary"
          },
          "receivables": {
            "description": "Receb\u00EDveis com vencimento no per\u00EDodo.",
            "$ref": "#/components/schemas/ReceivablesSummary"
          }
        },
        "additionalProperties": false,
        "description": "Resumo de vendas de um per\u00EDodo, com os mesmos n\u00FAmeros da tela Relat\u00F3rios, Vendas do Festero. Exige o escopo\r\n\u0060finance:read\u0060. Uma \u00FAnica chamada substitui percorrer todos os eventos e receb\u00EDveis."
      },
      "SoldEventsSummary": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Quantidade de eventos vendidos.",
            "format": "int32"
          },
          "total": {
            "description": "Soma do valor dos eventos vendidos.",
            "$ref": "#/components/schemas/Money"
          },
          "received": {
            "description": "Soma do que j\u00E1 foi recebido desses eventos, considerando os receb\u00EDveis n\u00E3o cancelados.",
            "$ref": "#/components/schemas/Money"
          },
          "balance": {
            "description": "Saldo a receber: \u0060total\u0060 menos \u0060received\u0060.",
            "$ref": "#/components/schemas/Money"
          }
        },
        "additionalProperties": false,
        "description": "Eventos vendidos no per\u00EDodo: os que est\u00E3o nas situa\u00E7\u00F5es Agendado e Realizado, pela data do evento."
      },
      "VisitView": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador da visita.",
            "format": "uuid"
          },
          "status": {
            "type": [
              "null",
              "string"
            ],
            "description": "Situa\u00E7\u00E3o: \u0060requested\u0060, \u0060scheduled\u0060, \u0060completed\u0060, \u0060noshow\u0060 ou \u0060cancelled\u0060."
          },
          "channel": {
            "type": [
              "null",
              "string"
            ],
            "description": "Canal de origem do agendamento: \u0060manual\u0060, \u0060public\u0060 ou \u0060salesbot\u0060."
          },
          "scheduledStart": {
            "type": [
              "null",
              "string"
            ],
            "description": "In\u00EDcio agendado (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "scheduledEnd": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fim agendado (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "opportunityId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Oportunidade de venda vinculada, quando houver.",
            "format": "uuid"
          },
          "client": {
            "description": "Cliente da visita.",
            "$ref": "#/components/schemas/Reference"
          },
          "cancelledAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante do cancelamento, quando a visita foi cancelada (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "createdAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da cria\u00E7\u00E3o (ISO 8601 com deslocamento).",
            "format": "date-time"
          },
          "updatedAt": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instante da \u00FAltima altera\u00E7\u00E3o (ISO 8601 com deslocamento). Nulo se nunca foi alterada.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Visita de um cliente interessado ao espa\u00E7o da empresa. Exige o escopo \u0060visits:read\u0060. Os hor\u00E1rios v\u00EAm em ISO 8601\r\ncom o deslocamento de Bras\u00EDlia. N\u00E3o traz telefone, e-mail, nome de contato, link de reuni\u00E3o nem anota\u00E7\u00F5es."
      },
      "WebhookEnvelopeDoc": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "description": "Identificador est\u00E1vel do evento. Use-o para deduplicar (\u00E9 o mesmo valor do cabe\u00E7alho \u0060Festero-Event-Id\u0060).",
            "format": "uuid"
          },
          "type": {
            "type": [
              "null",
              "string"
            ],
            "description": "Tipo do evento, por exemplo \u0060quote.accepted\u0060."
          },
          "occurred_at": {
            "type": "string",
            "description": "Quando o evento aconteceu, em UTC (ISO 8601).",
            "format": "date-time"
          },
          "workspace_id": {
            "type": "string",
            "description": "Identificador da empresa.",
            "format": "uuid"
          },
          "api_version": {
            "type": [
              "null",
              "string"
            ],
            "description": "Vers\u00E3o da API. Hoje \u00E9 \u0060v1\u0060."
          },
          "resource_url": {
            "type": [
              "null",
              "string"
            ],
            "description": "Endere\u00E7o do recurso na API. Busque o estado atual por ele, com a sua credencial."
          },
          "data": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {},
            "description": "Dados resumidos do evento: identificadores, situa\u00E7\u00E3o e datas. O conte\u00FAdo varia por tipo de evento."
          }
        },
        "additionalProperties": false,
        "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o."
      }
    },
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "description": "Token de acesso do endpoint de token do Festero (client credentials, v\u00E1lido por 60 minutos) ou chave MCP (\u0060fk_mcp_...\u0060).",
        "scheme": "bearer"
      }
    }
  },
  "security": [
    {
      "bearer": []
    }
  ],
  "tags": [
    {
      "name": "Conta",
      "description": "Verifica\u00E7\u00E3o de sa\u00FAde da API e identifica\u00E7\u00E3o da credencial usada na chamada."
    },
    {
      "name": "CRM",
      "description": "Oportunidades de venda e etapas do funil. Exige o escopo \u0060crm:read\u0060."
    },
    {
      "name": "Eventos",
      "description": "Eventos da empresa, s\u00F3 com os dados principais. Exige o escopo \u0060events:read\u0060."
    },
    {
      "name": "Or\u00E7amentos",
      "description": "Or\u00E7amentos com as op\u00E7\u00F5es e os itens de cada um. Exige o escopo \u0060quotes:read\u0060."
    },
    {
      "name": "Visitas",
      "description": "Visitas de clientes interessados ao espa\u00E7o da empresa. Exige o escopo \u0060visits:read\u0060."
    },
    {
      "name": "Financeiro",
      "description": "Receb\u00EDveis e resumo de vendas por per\u00EDodo. Exige o escopo \u0060finance:read\u0060."
    }
  ],
  "webhooks": {
    "event.created": {
      "post": {
        "summary": "Um evento foi criado.",
        "description": "Enviado quando isso acontece com um evento. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_event_created",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "event.status_changed": {
      "post": {
        "summary": "A situa\u00E7\u00E3o de um evento mudou (\u0060data.from\u0060, \u0060data.to\u0060).",
        "description": "Enviado quando isso acontece com um evento. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_event_status_changed",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "event.cancelled": {
      "post": {
        "summary": "Um evento foi cancelado ou exclu\u00EDdo (\u0060data.reason\u0060).",
        "description": "Enviado quando isso acontece com um evento. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_event_cancelled",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "quote.sent": {
      "post": {
        "summary": "Um or\u00E7amento foi enviado ao cliente ou renovado (\u0060data.reason\u0060 igual a \u0060renewed\u0060).",
        "description": "Enviado quando isso acontece com um or\u00E7amento. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_quote_sent",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "quote.accepted": {
      "post": {
        "summary": "Um or\u00E7amento foi aceito (\u0060data.event_id\u0060 quando um evento foi criado).",
        "description": "Enviado quando isso acontece com um or\u00E7amento. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_quote_accepted",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "quote.rejected": {
      "post": {
        "summary": "Um or\u00E7amento foi recusado.",
        "description": "Enviado quando isso acontece com um or\u00E7amento. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_quote_rejected",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "visit.scheduled": {
      "post": {
        "summary": "Uma visita foi agendada ou reagendada (\u0060data.rescheduled\u0060).",
        "description": "Enviado quando isso acontece com uma visita. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_visit_scheduled",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "visit.confirmed": {
      "post": {
        "summary": "Um pedido de visita foi confirmado pela empresa.",
        "description": "Enviado quando isso acontece com uma visita. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_visit_confirmed",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "visit.cancelled": {
      "post": {
        "summary": "Uma visita foi cancelada ou um pedido foi recusado (\u0060data.reason\u0060).",
        "description": "Enviado quando isso acontece com uma visita. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_visit_cancelled",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "opportunity.created": {
      "post": {
        "summary": "Uma oportunidade de venda foi criada.",
        "description": "Enviado quando isso acontece com uma oportunidade. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_opportunity_created",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "opportunity.stage_changed": {
      "post": {
        "summary": "Uma oportunidade mudou de etapa do funil (\u0060data.from_stage_id\u0060, \u0060data.to_stage_id\u0060).",
        "description": "Enviado quando isso acontece com uma oportunidade. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_opportunity_stage_changed",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "receivable.paid": {
      "post": {
        "summary": "Um receb\u00EDvel foi pago, total ou parcialmente (\u0060data.partial\u0060).",
        "description": "Enviado quando isso acontece com um receb\u00EDvel. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_receivable_paid",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    },
    "receivable.overdue": {
      "post": {
        "summary": "Um receb\u00EDvel venceu.",
        "description": "Enviado quando isso acontece com um receb\u00EDvel. O conte\u00FAdo \u00E9 enxuto: busque o estado atual em \u0060resource_url\u0060.",
        "operationId": "webhook_receivable_overdue",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "description": "Envelope comum a todos os eventos de webhook, enviado como corpo JSON da requisi\u00E7\u00E3o.",
                "$ref": "#/components/schemas/WebhookEnvelopeDoc"
              }
            }
          },
          "required": true
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em at\u00E9 10 segundos e processe depois."
          }
        }
      }
    }
  }
}
