{
  "openapi": "3.1.0",
  "info": {
    "title": "AtendroZAP — integração Atendro",
    "version": "2026-09-17",
    "description": "Contrato auditado contra o router deste repositório. Servidor em fase laboratory. Testes HTTP usam stores/sessões sintéticos; não equivalem a homologação no WhatsApp real. Consultar ATENDRO_INTEGRATION.md, API_ENDPOINTS.md e PILOT_GATES.md. Nenhuma credencial real é incluída. /metrics tem listener próprio e não faz parte desta base URL. Webhook global configurável por servidor em /v1/webhook, com herança e exceções por instância. Documentação central em https://wpp.atendro.cloud/docs; OpenAPI e llms.txt no mesmo domínio. As chamadas REST usam a URL e as credenciais do servidor selecionado."
  },
  "externalDocs": {
    "description": "Documentação central de integração do AtendroZAP",
    "url": "https://wpp.atendro.cloud/docs"
  },
  "servers": [
    {
      "url": "http://127.0.0.1:8091",
      "description": "Padrão local; usar somente ambiente descartável para testes."
    },
    {
      "url": "https://1.atendro.cloud",
      "description": "Servidor 1; readiness verificada em 17/09/2026. Não executar mutações/pareamento sem autorização explícita."
    }
  ],
  "tags": [
    {
      "name": "Diagnóstico"
    },
    {
      "name": "Instâncias"
    },
    {
      "name": "Administração"
    },
    {
      "name": "Mensagens"
    },
    {
      "name": "Consultas"
    },
    {
      "name": "Mídia"
    },
    {
      "name": "Leitura"
    },
    {
      "name": "Grupos"
    },
    {
      "name": "Proxy"
    },
    {
      "name": "Webhooks"
    },
    {
      "name": "Ligações"
    }
  ],
  "paths": {
    "/health/live": {
      "get": {
        "operationId": "healthLive",
        "tags": [
          "Diagnóstico"
        ],
        "summary": "Verificar processo HTTP",
        "description": "Sem autenticação; não atesta banco nem WhatsApp.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Verificar processo HTTP",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestLivenessAndReadiness"
        ]
      }
    },
    "/health/ready": {
      "get": {
        "operationId": "healthReady",
        "tags": [
          "Diagnóstico"
        ],
        "summary": "Verificar banco acessível",
        "description": "200 não significa instância conectada nem integração homologada.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Verificar banco acessível",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "description": "Banco inacessível: status=not_ready, reason=database_unreachable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestLivenessAndReadiness"
        ]
      }
    },
    "/v1/capabilities": {
      "get": {
        "operationId": "getCapabilities",
        "tags": [
          "Diagnóstico"
        ],
        "summary": "Consultar capacidades",
        "description": "Fonte para habilitar funcionalidades. Para voz, exigir capabilities.calls=true e instance_kinds contendo calls. status=laboratory.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar capacidades",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Capabilities"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCapabilitiesReportLaboratoryScope",
          "TestInitCreatesCallsInstances"
        ]
      }
    },
    "/instance/init": {
      "post": {
        "operationId": "createInstance",
        "tags": [
          "Instâncias"
        ],
        "summary": "Criar instância e emitir token",
        "description": "Não pareia nem conecta. Guardar instance.id e instance.token no backend; listar não recupera o token. kind=whatsapp por padrão; kind=calls cria um dispositivo vinculado próprio para voz. callsMaxConcurrent define o limite próprio de 1 a 8 para calls; omitido, usa o padrão do servidor.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Criar instância e emitir token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InitResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "invalid_name, invalid_kind, invalid_calls_max_concurrent ou invalid_json.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "calls_not_supported ao solicitar kind=calls com o módulo desligado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestInitCreatesInstanceAndReturnsTokenOnce",
          "TestInitValidatesNames",
          "TestIdempotentSendAndInit",
          "TestInitCreatesCallsInstances",
          "TestInstanceCallSettings",
          "TestCallSettingsDefaultAndLegacyInstances"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InitRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 900
      }
    },
    "/instance/all": {
      "get": {
        "operationId": "listInstances",
        "tags": [
          "Instâncias"
        ],
        "summary": "Listar instâncias do servidor",
        "description": "Array direto. Nunca inclui token; qrcode é vazio. companyId é filtro administrativo, não isolamento de autenticação.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "companyId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listar instâncias do servidor",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Instance"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestInitCreatesInstanceAndReturnsTokenOnce"
        ]
      }
    },
    "/instance/connect": {
      "post": {
        "operationId": "connectInstance",
        "tags": [
          "Instâncias"
        ],
        "summary": "Conectar ou iniciar pareamento",
        "description": "Abre conexão real; exige autorização para laboratório. Aguarda até 5 s por QR/login; acompanhar /instance/status. Sem phone: QR; com phone: paircode.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Conectar ou iniciar pareamento",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connection"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestConnectReturnsRenderedQRCode",
          "TestConnectValidatesPairingPhone"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectRequest"
              }
            }
          }
        }
      }
    },
    "/instance/status": {
      "get": {
        "operationId": "getInstanceStatus",
        "tags": [
          "Instâncias"
        ],
        "summary": "Consultar sessão e webhook",
        "description": "Sem iniciar conexão. Usar connected e loggedIn; QR/código podem estar presentes durante pareamento.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar sessão e webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connection"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestStatusReportsConnectedSession",
          "TestStatusExposesDisconnectCodeAndLimits"
        ]
      }
    },
    "/instance/disconnect": {
      "post": {
        "operationId": "disconnectInstance",
        "tags": [
          "Instâncias"
        ],
        "summary": "Desvincular e limpar credencial",
        "description": "Logout, distinto de restart. unlinked informa confirmação remota.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Desvincular e limpar credencial",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DisconnectResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestDisconnectRestartAndDelete"
        ]
      }
    },
    "/instance/restart": {
      "post": {
        "operationId": "restartInstance",
        "tags": [
          "Instâncias"
        ],
        "summary": "Reiniciar preservando credencial",
        "description": "Reabre sessão; não usar como rotina de validação de cadastro.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Reiniciar preservando credencial",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestartResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestDisconnectRestartAndDelete"
        ]
      }
    },
    "/instance": {
      "delete": {
        "operationId": "deleteInstance",
        "tags": [
          "Instâncias"
        ],
        "summary": "Excluir instância",
        "description": "Logout em melhor esforço e exclusão definitiva; somente após autorização do responsável.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Excluir instância",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseMessage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestDisconnectRestartAndDelete"
        ]
      }
    },
    "/v1/instances/{id}": {
      "get": {
        "operationId": "adminGetInstance",
        "tags": [
          "Administração"
        ],
        "summary": "Consultar instância por ID",
        "description": "Ação administrativa com admintoken, sem precisar do token da instância. Mesmos efeitos da rota de instância.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar instância por ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connection"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestAdminRoutesByInstanceID"
        ]
      },
      "delete": {
        "operationId": "adminDeleteInstance",
        "tags": [
          "Administração"
        ],
        "summary": "Excluir instância por ID",
        "description": "Ação administrativa com admintoken, sem precisar do token da instância. Mesmos efeitos da rota de instância.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Excluir instância por ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResponseMessage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestAdminRoutesByInstanceID"
        ]
      }
    },
    "/v1/instances/{id}/connect": {
      "post": {
        "operationId": "adminConnectInstance",
        "tags": [
          "Administração"
        ],
        "summary": "Conectar instância por ID",
        "description": "Ação administrativa com admintoken, sem precisar do token da instância. Mesmos efeitos da rota de instância.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Conectar instância por ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Connection"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestAdminRoutesByInstanceID"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectRequest"
              }
            }
          }
        }
      }
    },
    "/v1/instances/{id}/disconnect": {
      "post": {
        "operationId": "adminDisconnectInstance",
        "tags": [
          "Administração"
        ],
        "summary": "Desvincular instância por ID",
        "description": "Ação administrativa com admintoken, sem precisar do token da instância. Mesmos efeitos da rota de instância.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Desvincular instância por ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DisconnectResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestAdminRoutesByInstanceID"
        ]
      }
    },
    "/v1/instances/{id}/restart": {
      "post": {
        "operationId": "adminRestartInstance",
        "tags": [
          "Administração"
        ],
        "summary": "Reiniciar instância por ID",
        "description": "Ação administrativa com admintoken, sem precisar do token da instância. Mesmos efeitos da rota de instância.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Reiniciar instância por ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestartResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestAdminRoutesByInstanceID"
        ]
      }
    },
    "/v1/instances/{id}/token": {
      "post": {
        "operationId": "adminReissueToken",
        "tags": [
          "Administração"
        ],
        "summary": "Reemitir token da instância",
        "description": "O novo segredo aparece nesta resposta. graceSeconds=0 revoga o anterior imediatamente; máximo 3600. Não possui idempotência.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Reemitir token da instância",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "description": "whatsapp_unreachable ou storage_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Corpo ou telefone inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "session_owned_elsewhere ou outro conflito de sessão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "worker_full; Retry-After=5.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestTokenReissueByInstanceID"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          }
        }
      }
    },
    "/admin/restart": {
      "post": {
        "operationId": "adminRestartWorker",
        "tags": [
          "Administração"
        ],
        "summary": "Reiniciar sessões deste worker",
        "description": "Soft restart das sessões do worker que atende a requisição. Não reinicia processo nem todos os workers do cluster.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "202": {
            "description": "Reiniciar sessões deste worker",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminRestartResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestChatFindAndAdminRoutes"
        ]
      }
    },
    "/send/text": {
      "post": {
        "operationId": "sendText",
        "tags": [
          "Mensagens"
        ],
        "summary": "Enviar texto",
        "description": "Retorna ID real do WhatsApp, não ID de fila. linkPreview é ignorado.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Enviar texto",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestSendTextReturnsRealMessageID",
          "TestSendTextMapsSessionErrors",
          "TestIdempotentSendAndInit"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendTextRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/send/media": {
      "post": {
        "operationId": "sendMedia",
        "tags": [
          "Mensagens"
        ],
        "summary": "Enviar mídia",
        "description": "URL depende da allowlist de mídia. PTT requer OGG/Opus; sem transcodificação outros formatos saem como áudio comum.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Enviar mídia",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendMediaResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestSendMediaValidatesAndForwards",
          "TestSendMediaFromAllowlistedURL"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMediaRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/send/contact": {
      "post": {
        "operationId": "sendContact",
        "tags": [
          "Mensagens"
        ],
        "summary": "Enviar contato",
        "description": "Contato vCard; number é o destinatário e phoneNumber é o telefone do contato.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Enviar contato",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestSendContactAndLocation"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendContactRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/send/location": {
      "post": {
        "operationId": "sendLocation",
        "tags": [
          "Mensagens"
        ],
        "summary": "Enviar localização",
        "description": "Coordenadas obrigatórias; suporta citação e marca de encaminhada.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Enviar localização",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestSendContactAndLocation"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendLocationRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/send/menu": {
      "post": {
        "operationId": "sendMenu",
        "tags": [
          "Mensagens"
        ],
        "summary": "Enviar botões, lista ou enquete",
        "description": "renderMode=auto tenta nativo e pode cair para enquete/texto. rendered informa o formato entregue. 3 botões; 4–10 respostas podem virar lista; até 10 linhas; enquetes 2–12 opções. call: e carousel recusados.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Enviar botões, lista ou enquete",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendMenuResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestSendMenuParsesLegacyChoices"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMenuRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/message/forward": {
      "post": {
        "operationId": "forwardMessage",
        "tags": [
          "Mensagens"
        ],
        "summary": "Encaminhar mensagem guardada",
        "description": "Rota própria do AtendroZAP. Faz novo envio; mídias são baixadas e reenviadas, com marca de encaminhada.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Encaminhar mensagem guardada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "message_not_found ou media_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestMessageActionRoutes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForwardRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/message/react": {
      "post": {
        "operationId": "reactMessage",
        "tags": [
          "Mensagens"
        ],
        "summary": "Reagir ou remover reação",
        "description": "Chat vem do ID guardado; number é ignorado. text vazio remove a reação.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Reagir ou remover reação",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReactResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "message_not_found ou media_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestMessageActionRoutes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReactRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/message/delete": {
      "post": {
        "operationId": "deleteMessage",
        "tags": [
          "Mensagens"
        ],
        "summary": "Apagar mensagem própria para todos",
        "description": "Mensagem recebida retorna cannot_delete. recorded=false indica WhatsApp aceitou mas o banco não gravou. Repetida pode retornar alreadyDeleted.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Apagar mensagem própria para todos",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteMessageResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "message_not_found ou media_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestMessageActionRoutes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteMessageRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/message/edit": {
      "post": {
        "operationId": "editMessage",
        "tags": [
          "Mensagens"
        ],
        "summary": "Editar texto ou legenda própria",
        "description": "Janela de 20 min. id/messageid do resultado identificam o original; editId identifica a ação. recorded=false exige reconciliação.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Editar texto ou legenda própria",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "message_not_found ou media_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestMessageActionRoutes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      },
      "put": {
        "operationId": "editMessagePut",
        "tags": [
          "Mensagens"
        ],
        "summary": "Editar mensagem (alias PUT)",
        "description": "Mesmo contrato de POST /message/edit. Trocar POST por PUT com a mesma Idempotency-Key muda o hash da requisição.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Editar mensagem (alias PUT)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EditResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Entrada inválida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "body_too_large ou mídia acima do limite.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "too_many_requests ou retry_later: nada enviado, respeitar Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "whatsapp_reachout_timelock / WHATSAPP_REACHOUT_TIMELOCK, provider_code=463.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "send_ambiguous ou action_ambiguous com ID. Reconciliar antes de repetir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestMessageActionRoutes"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/message/find": {
      "post": {
        "operationId": "findMessages",
        "tags": [
          "Consultas"
        ],
        "summary": "Buscar mensagens no formato legado",
        "description": "Ordem mais recente primeiro. includeHistory=true por padrão; histórico nunca dispara automações novas. id ausente no store retorna messages=[].",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Buscar mensagens no formato legado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindMessagesResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "invalid_limit ou invalid_chatid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestFindMessagesLegacyShape",
          "TestPhoneChatFiltersResolveThroughTheSession"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindMessagesRequest"
              }
            }
          }
        }
      }
    },
    "/message/status/{id}": {
      "get": {
        "operationId": "getMessageStatus",
        "tags": [
          "Consultas"
        ],
        "summary": "Consultar resultado da mensagem",
        "description": "Estados internos em minúsculas; usar para reconciliar resultado ambíguo. Preferir ID bruto messageid devolvido no envio.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar resultado da mensagem",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "description": "message_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestMessageListingStatusAndEvents"
        ]
      }
    },
    "/v1/messages": {
      "get": {
        "operationId": "listStoredMessages",
        "tags": [
          "Consultas"
        ],
        "summary": "Listar mensagens no formato interno",
        "description": "Até 200, sem offset. Para paginação e formato legado use /message/find.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "chatid",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Filtro exato do store; preferir JID."
            }
          },
          {
            "name": "excludeHistory",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listar mensagens no formato interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListMessagesResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestMessageListingStatusAndEvents"
        ]
      }
    },
    "/message/download": {
      "post": {
        "operationId": "downloadMessageMedia",
        "tags": [
          "Mídia"
        ],
        "summary": "Obter link assinado de mídia",
        "description": "Pode buscar mídia no WhatsApp e pedir reenvio ao celular; não é uma consulta sem efeitos. Link vence com retenção de 48 h, use expiresAt.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Obter link assinado de mídia",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DownloadResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "invalid_id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "message_not_found ou media_unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "media_reupload_pending; aguardar reenvio ao celular.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "media_too_large; limite 64 MiB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "not_media.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestDownloadAndServeMedia"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DownloadRequest"
              }
            }
          }
        }
      }
    },
    "/v1/media/{token}": {
      "get": {
        "operationId": "getSignedMedia",
        "tags": [
          "Mídia"
        ],
        "summary": "Ler bytes pelo link assinado",
        "description": "Sem header token: a credencial é o token na URL assinada devolvida pela API. Não registrar/compartilhar o link. Expirado ou inválido retorna 404. Não aceita upload.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "Token assinado do fileURL; usar a URL inteira devolvida pelo download."
          }
        ],
        "responses": {
          "200": {
            "description": "Bytes da mídia; Content-Length presente. Tipos passivos inline; conteúdo ativo vira attachment/application/octet-stream com CSP sandbox.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "description": "Link inválido, expirado ou mídia não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestDownloadAndServeMedia"
        ]
      }
    },
    "/message/markread": {
      "post": {
        "operationId": "markMessagesRead",
        "tags": [
          "Leitura"
        ],
        "summary": "Enviar recibos de leitura por ID",
        "description": "Até 1000 IDs; mensagens próprias e desconhecidas são ignoradas. Afeta leitura no WhatsApp.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Enviar recibos de leitura por ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarkReadResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestReadCheckAndDetails"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MarkReadRequest"
              }
            }
          }
        }
      }
    },
    "/chat/read": {
      "post": {
        "operationId": "markChatRead",
        "tags": [
          "Leitura"
        ],
        "summary": "Marcar recebidas do chat como lidas",
        "description": "Envia recibo para até 100 mensagens ainda não lidas. read=false retorna marked=0 e note; não há suporte a marcar como não lido.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Marcar recebidas do chat como lidas",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatReadResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestReadCheckAndDetails"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatReadRequest"
              }
            }
          }
        }
      }
    },
    "/chat/check": {
      "post": {
        "operationId": "checkNumbers",
        "tags": [
          "Consultas"
        ],
        "summary": "Verificar números no WhatsApp",
        "description": "1–50 telefones; number é alias singular de numbers. Exige sessão conectada.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Verificar números no WhatsApp",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NumberCheck"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestReadCheckAndDetails"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckRequest"
              }
            }
          }
        }
      }
    },
    "/chat/details": {
      "post": {
        "operationId": "getChatDetails",
        "tags": [
          "Consultas"
        ],
        "summary": "Obter identidade e foto",
        "description": "Foto em cache por 24 h; campos vazios dependem de privacidade do WhatsApp. Não devolver dados de terceiros em logs.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Obter identidade e foto",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatDetails"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "description": "number_not_on_whatsapp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestReadCheckAndDetails"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DetailsRequest"
              }
            }
          }
        }
      }
    },
    "/chat/find": {
      "post": {
        "operationId": "findChats",
        "tags": [
          "Consultas"
        ],
        "summary": "Listar conversas conhecidas",
        "description": "Não consulta histórico remoto sob demanda. wa_lastMsgTimestamp e wa_lastMessageTime estão em segundos. Sem filtros de lead/etiqueta.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Listar conversas conhecidas",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindChatsResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestChatFindAndAdminRoutes"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindChatsRequest"
              }
            }
          }
        }
      }
    },
    "/group/list": {
      "get": {
        "operationId": "listGroups",
        "tags": [
          "Grupos"
        ],
        "summary": "Listar grupos sincronizados",
        "description": "Contrato implementado; homologação real de grupos pendente. force=true consulta WhatsApp; noparticipants=true omite Participants.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "force",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "noparticipants",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listar grupos sincronizados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "groups": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Group"
                      }
                    }
                  },
                  "required": [
                    "groups"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Grupo, participantes, nome ou imagem inválidos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "not_in_group ou not_admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "group_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Sessão desconectada/ocupada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, Retry-After=30.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGroupRoutesFollowTheLegacyContract"
        ]
      }
    },
    "/group/info": {
      "post": {
        "operationId": "getGroupInfo",
        "tags": [
          "Grupos"
        ],
        "summary": "Consultar grupo",
        "description": "Cache de 10 min; force=true atualiza. getInviteLink só retorna link para administrador. getRequestsParticipants ignorado.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar grupo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Grupo, participantes, nome ou imagem inválidos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "not_in_group ou not_admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "group_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Sessão desconectada/ocupada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, Retry-After=30.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGroupRoutesFollowTheLegacyContract"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupInfoRequest"
              }
            }
          }
        }
      }
    },
    "/group/create": {
      "post": {
        "operationId": "createGroup",
        "tags": [
          "Grupos"
        ],
        "summary": "Criar grupo",
        "description": "Nome até 100 caracteres e até 50 participantes na criação. Conferir Error por participante. Exige autorização para grupo de teste.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Criar grupo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Grupo, participantes, nome ou imagem inválidos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "not_in_group ou not_admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "group_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, Retry-After=30.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGroupRoutesFollowTheLegacyContract"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGroupRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/group/updateParticipants": {
      "post": {
        "operationId": "updateGroupParticipants",
        "tags": [
          "Grupos"
        ],
        "summary": "Alterar participantes",
        "description": "add/remove/promote/demote. approve/reject retornam 400 invalid_action. Conferir Error por participante e atualizar o grupo.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Alterar participantes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupParticipantsResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Grupo, participantes, nome ou imagem inválidos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "not_in_group ou not_admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "group_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, Retry-After=30.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGroupRoutesFollowTheLegacyContract"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupParticipantsRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/group/updateName": {
      "post": {
        "operationId": "updateGroupName",
        "tags": [
          "Grupos"
        ],
        "summary": "Alterar nome do grupo",
        "description": "Nome até 100 caracteres. Efeito real em grupo; homologação de laboratório pendente.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Alterar nome do grupo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupUpdateResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Grupo, participantes, nome ou imagem inválidos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "not_in_group ou not_admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "group_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, Retry-After=30.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGroupRoutesFollowTheLegacyContract"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupNameRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/group/updateImage": {
      "post": {
        "operationId": "updateGroupImage",
        "tags": [
          "Grupos"
        ],
        "summary": "Alterar imagem do grupo",
        "description": "JPEG/PNG/GIF até 8 MiB; corpo JSON até 12 MiB; convertido em JPEG até 640×640. remove/delete removem a foto.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Alterar imagem do grupo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupUpdateResult"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true quando a resposta guardada foi repetida.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "Grupo, participantes, nome ou imagem inválidos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "not_in_group ou not_admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "group_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflito de sessão ou idempotency_in_progress; respeitar o código error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, Retry-After=30.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "image_too_large ou body_too_large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "invalid_image.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Falha semântica da operação ou idempotency_mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGroupRoutesFollowTheLegacyContract"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupImageRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/instance/proxy": {
      "get": {
        "operationId": "getInstanceProxy",
        "tags": [
          "Proxy"
        ],
        "summary": "Consultar proxy da instância",
        "description": "Credenciais da URL são redigidas; não há pool gerenciado nem fallback automático.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar proxy da instância",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Proxy"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestInstanceProxyRoutes"
        ]
      },
      "post": {
        "operationId": "setInstanceProxy",
        "tags": [
          "Proxy"
        ],
        "summary": "Configurar proxy ou conexão direta",
        "description": "custom sonda conectividade antes de gravar. internal significa conexão direta; none exige confirm_no_proxy=true. Mudança pode reiniciar sessão; não usar para testar cadastro.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Configurar proxy ou conexão direta",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProxyResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "proxy_unreachable, invalid_proxy_url, invalid_mode ou confirm_no_proxy_required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "proxy_required ou secret_unreadable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestInstanceProxyRoutes",
          "TestProxyRequiredWorkerRefusesDirectMode"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProxyRequest"
              }
            }
          }
        }
      }
    },
    "/webhook": {
      "post": {
        "operationId": "configureWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Configurar, desativar ou herdar webhook",
        "description": "Um destino efetivo por instância. Cadastro cria exceção ao global. URL nova começa após o backlog; mesma URL preserva cursor e segredo omitido. action=delete desativa inclusive em mudanças globais; action=inherit volta ao global. groups e call são entregues; qrcode continua ignorado. call é emitido pelas instâncias calls.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Cadastrar, atualizar ou remover webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookWriteResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "invalid_url/event/events/exclude/secret, invalid_action ou unsupported_option.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "webhooks_disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestWebhookRegistrationAndEvents",
          "TestCallWebhookSubscription",
          "TestWebhooksAreIsolatedByInstance"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookRequest"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Consultar webhook e entrega",
        "description": "Sem cadastro: registered=false, webhooks=[]. Com cadastro inclui webhooks=[registro] e deliveryStatus. Nunca revela o secret.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar webhook e entrega",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestWebhookRegistrationAndEvents",
          "TestWebhooksAreIsolatedByInstance"
        ]
      }
    },
    "/webhook/errors": {
      "get": {
        "operationId": "getWebhookErrors",
        "tags": [
          "Webhooks"
        ],
        "summary": "Consultar falhas recentes de entrega",
        "description": "Falhas deste worker, sem payload; também inclui estado persistido quando houver webhook.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar falhas recentes de entrega",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookErrors"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestWebhookRegistrationAndEvents"
        ]
      }
    },
    "/v1/events": {
      "get": {
        "operationId": "listEvents",
        "tags": [
          "Webhooks"
        ],
        "summary": "Inspecionar eventos internos e fila",
        "description": "Formato persistido difere do envelope legado entregue. Consultar EVENTS.md. Não expor payloads em logs.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "delivered",
                "dead"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Inspecionar eventos internos e fila",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventsResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestMessageListingStatusAndEvents",
          "TestWebhookRegistrationAndEvents"
        ]
      }
    },
    "/v1/events/{id}/replay": {
      "post": {
        "operationId": "replayEvent",
        "tags": [
          "Webhooks"
        ],
        "summary": "Reenfileirar evento",
        "description": "Reinicia orçamento de tentativas; pode repetir automações no consumidor. Deduplicar pelo ID do evento. Exige avaliação antes do replay real.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Reenfileirar evento",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReplayResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "description": "event_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "event_before_registration; anterior ao webhook atual ou sem webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestWebhookRegistrationAndEvents"
        ]
      }
    },
    "/call/make": {
      "post": {
        "operationId": "makeCall",
        "tags": [
          "Ligações"
        ],
        "summary": "Iniciar ligação por instância calls",
        "description": "Exige kind=calls conectado e módulo ligado. Retorna 201 ao iniciar; acompanhar o estado. video: true inicia uma chamada de vídeo (exige capabilities.calls_video). Em instância whatsapp mantém 501 calls_not_supported. Não equivale à chamada sem áudio do provedor legado.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "line_busy, not_connected, owned_elsewhere ou idempotency_in_progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "calls_not_supported: módulo desligado; /call/make também recusa instância whatsapp. calls_video_not_supported: video=true sem o recurso no worker.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "201": {
            "description": "Chamada iniciada; acompanhar pelo callId.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Call"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "description": "true ao repetir a resposta guardada.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "invalid_number ou invalid_json.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "number_not_on_whatsapp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "idempotency_mismatch: chave repetida com corpo diferente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "call_failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "retry_later antes de iniciar a chamada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallRoutesOnACallsInstance",
          "TestCallRoutesAreGatedByKind",
          "TestCallRoutesMapSessionErrors"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MakeCallRequest"
              }
            }
          }
        },
        "x-idempotency-retention-seconds": 86400
      }
    },
    "/v1/webhook": {
      "post": {
        "operationId": "configureGlobalWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Salvar ou remover webhook global",
        "description": "Configuração persistida por servidor. Instâncias sem exceção herdam automaticamente. Atualização transacional preserva configurações próprias. action=delete limpa o global; a configuração salva prevalece sobre bootstrap por ambiente. Segredo nunca é devolvido.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Salvar ou remover webhook global",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GlobalWebhook"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "invalid_url/event/events/exclude/secret, invalid_action ou unsupported_option.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "webhooks_disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGlobalAndAdminWebhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GlobalWebhookRequest"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getGlobalWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Consultar webhook global",
        "description": "Configuração persistida por servidor. Instâncias sem exceção herdam automaticamente. Atualização transacional preserva configurações próprias. action=delete limpa o global; a configuração salva prevalece sobre bootstrap por ambiente. Segredo nunca é devolvido.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar webhook global",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GlobalWebhook"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGlobalAndAdminWebhooks"
        ]
      }
    },
    "/v1/instances/{id}/webhook": {
      "post": {
        "operationId": "adminConfigureWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Configurar, desativar ou herdar webhook por ID",
        "description": "Um destino efetivo por instância. Cadastro cria exceção ao global. URL nova começa após o backlog; mesma URL preserva cursor e segredo omitido. action=delete desativa inclusive em mudanças globais; action=inherit volta ao global. groups e call são entregues; qrcode continua ignorado. call é emitido pelas instâncias calls.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Cadastrar, atualizar ou remover webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookWriteResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "400": {
            "description": "invalid_url/event/events/exclude/secret, invalid_action ou unsupported_option.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "webhooks_disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGlobalAndAdminWebhooks",
          "TestWebhooksAreIsolatedByInstance"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookRequest"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "adminGetWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Consultar webhook e entrega por ID",
        "description": "Sem cadastro: registered=false, webhooks=[]. Com cadastro inclui webhooks=[registro] e deliveryStatus. Nunca revela o secret.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar webhook e entrega",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGlobalAndAdminWebhooks",
          "TestWebhooksAreIsolatedByInstance"
        ]
      }
    },
    "/v1/instances/{id}/webhook/errors": {
      "get": {
        "operationId": "adminGetWebhookErrors",
        "tags": [
          "Webhooks"
        ],
        "summary": "Consultar falhas recentes de entrega por ID",
        "description": "Falhas deste worker, sem payload; também inclui estado persistido quando houver webhook.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Consultar falhas recentes de entrega",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookErrors"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "description": "instance_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestGlobalAndAdminWebhooks"
        ]
      }
    },
    "/call/answer": {
      "post": {
        "operationId": "answerCall",
        "tags": [
          "Ligações"
        ],
        "summary": "Atender ligação recebida",
        "description": "Token da instância calls que possui a chamada. Corpo com callId; a operação renova o lease antes do efeito externo.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou invalid_call_state; conferir error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "calls_not_supported: módulo desligado; /call/make também recusa instância whatsapp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "200": {
            "description": "Estado da chamada após a ação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Call"
                }
              }
            }
          },
          "400": {
            "description": "invalid_json ou invalid_call_id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "call_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "retry_later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallRoutesOnACallsInstance",
          "TestCallRoutesAreGatedByKind",
          "TestCallRoutesMapSessionErrors"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallActionRequest"
              }
            }
          }
        }
      }
    },
    "/call/reject": {
      "post": {
        "operationId": "rejectCall",
        "tags": [
          "Ligações"
        ],
        "summary": "Recusar ligação recebida",
        "description": "Token da instância calls que possui a chamada. Corpo com callId; a operação renova o lease antes do efeito externo.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou invalid_call_state; conferir error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "calls_not_supported: módulo desligado; /call/make também recusa instância whatsapp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "200": {
            "description": "Estado da chamada após a ação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Call"
                }
              }
            }
          },
          "400": {
            "description": "invalid_json ou invalid_call_id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "call_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "retry_later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallRoutesOnACallsInstance",
          "TestCallRoutesAreGatedByKind",
          "TestCallRoutesMapSessionErrors"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallActionRequest"
              }
            }
          }
        }
      }
    },
    "/call/hangup": {
      "post": {
        "operationId": "hangupCall",
        "tags": [
          "Ligações"
        ],
        "summary": "Encerrar ligação",
        "description": "Token da instância calls que possui a chamada. Corpo com callId; a operação renova o lease antes do efeito externo.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou invalid_call_state; conferir error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "calls_not_supported: módulo desligado; /call/make também recusa instância whatsapp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "200": {
            "description": "Estado da chamada após a ação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Call"
                }
              }
            }
          },
          "400": {
            "description": "invalid_json ou invalid_call_id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "call_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "retry_later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallRoutesOnACallsInstance",
          "TestCallRoutesAreGatedByKind",
          "TestCallRoutesMapSessionErrors"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallActionRequest"
              }
            }
          }
        }
      }
    },
    "/call/active": {
      "get": {
        "operationId": "listActiveCalls",
        "tags": [
          "Ligações"
        ],
        "summary": "Listar ligações ativas",
        "description": "Lista as chamadas vivas da instância calls neste worker.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou invalid_call_state; conferir error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "calls_not_supported: módulo desligado; /call/make também recusa instância whatsapp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "200": {
            "description": "Chamadas vivas.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveCalls"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallRoutesOnACallsInstance",
          "TestCallRoutesAreGatedByKind"
        ]
      }
    },
    "/call/{id}": {
      "get": {
        "operationId": "getCall",
        "tags": [
          "Ligações"
        ],
        "summary": "Consultar estado de ligação",
        "description": "Consulta a chamada viva ou seu histórico persistente, com recording (WAV) e videoRecording opcional (MP4) independentes. Continua disponível após desconexão/reinício e após expirar os arquivos.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "callId retornado pela API."
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou invalid_call_state; conferir error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "200": {
            "description": "Estado da chamada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Call"
                }
              }
            }
          },
          "404": {
            "description": "call_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallRoutesOnACallsInstance"
        ]
      }
    },
    "/call/{id}/audio": {
      "get": {
        "operationId": "streamCallAudio",
        "tags": [
          "Ligações"
        ],
        "summary": "Abrir ponte WebSocket de áudio",
        "description": "Upgrade WebSocket. PCM s16le mono 16 kHz binário nos dois sentidos; origem validada por ATENDROZAP_CALLS_AUDIO_ORIGINS. Aceita token no header ou na query somente nesta rota. O console faz proxy com o header e guarda o token fora do navegador. Perder o socket mantém a chamada por 30 segundos aguardando reconexão com o mesmo callId; um novo socket de áudio cancela o prazo e substitui o primeiro. Sem retorno, encerra com hangup/local. Para desligar voluntariamente, use POST /call/hangup. Códigos 4000 encerrada, 4001 PCM ímpar, 4002 falha de escrita, 4003 substituído.",
        "security": [
          {
            "InstanceToken": []
          },
          {
            "InstanceQueryToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "callId retornado pela API."
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou invalid_call_state; conferir error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "calls_not_supported: módulo desligado; /call/make também recusa instância whatsapp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "101": {
            "description": "WebSocket estabelecido; mensagens binárias PCM."
          },
          "400": {
            "description": "Upgrade WebSocket inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Origem de navegador não autorizada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "call_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallAudioAcceptsTheTokenInTheQuery",
          "TestCallRoutesAreGatedByKind"
        ]
      }
    },
    "/call/history": {
      "get": {
        "operationId": "listCallHistory",
        "tags": [
          "Ligações"
        ],
        "summary": "Consultar histórico de chamadas",
        "description": "Histórico persistente da instância, do mais novo ao mais antigo. Independente da conexão e da retenção de eventos/áudio. Paginação por before/nextCursor; não aceita token na query.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Itens por página.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "Cursor nextCursor da página anterior.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "required": false,
            "description": "Direção da chamada.",
            "schema": {
              "type": "string",
              "enum": [
                "inbound",
                "outbound"
              ]
            }
          },
          {
            "name": "answered",
            "in": "query",
            "required": false,
            "description": "Filtra pela ocorrência do atendimento.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Estado atual/final.",
            "schema": {
              "type": "string",
              "enum": [
                "ringing",
                "connecting",
                "active",
                "ended"
              ]
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do intervalo, inclusivo.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do intervalo, exclusivo.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou invalid_call_state; conferir error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "200": {
            "description": "Página do histórico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallHistory"
                }
              }
            }
          },
          "400": {
            "description": "invalid_filter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallHistoryRoutesArePrivateAndWorkOffline",
          "TestCallHistoryFilters"
        ]
      }
    },
    "/call/{id}/recording": {
      "get": {
        "operationId": "downloadCallRecording",
        "tags": [
          "Ligações"
        ],
        "summary": "Ouvir ou baixar gravação",
        "description": "WAV PCM 16-bit 16 kHz estéreo: atendente à esquerda, contato à direita. Header token obrigatório; query token recusada. Suporta Range. Cache privado desabilitado. Somente no worker onde o arquivo está armazenado; use proxy autenticado no sistema consumidor.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "callId retornado pela API."
          },
          {
            "name": "Range",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Intervalo HTTP de bytes para reprodução/seek."
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou invalid_call_state; conferir error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "200": {
            "description": "Gravação pronta.",
            "content": {
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "call_not_found ou recording_not_available."
          },
          "206": {
            "description": "Intervalo de bytes da gravação.",
            "content": {
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "410": {
            "description": "recording_expired: áudio fora do prazo de retenção."
          },
          "416": {
            "description": "Intervalo de bytes inválido."
          },
          "503": {
            "description": "recording_unavailable_on_worker ou recording_file_unavailable."
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallRecordingFilesArePrivate",
          "TestCallHistoryRoutesArePrivateAndWorkOffline"
        ]
      }
    },
    "/instance/call-settings": {
      "post": {
        "operationId": "configureInstanceCalls",
        "tags": [
          "Ligações"
        ],
        "summary": "Configurar limite e comportamento das chamadas recebidas da instância",
        "description": "Persiste parcialmente callsMaxConcurrent e/ou incomingCallMode, mesmo desconectada, sem iniciar chamadas ou reiniciar a sessão. Campos omitidos permanecem. expectedCallsConfigVersion opcional exige a versão atual e retorna 409 settings_version_conflict em divergência. Cada POST aceito incrementa callsConfigVersion e grava atomicamente call_settings com limite e modo, mesmo repetindo valores. Alterações de modo valem para novas chamadas. O worker local aplica imediatamente; outro worker aplica na renovação do lease. Rejeições automáticas geram histórico e evento, inclusive quando ocupado, sem consumir uma vaga de atendimento. reject_reply somente solicita resposta ao consumidor: a instância calls não envia texto. A integração deve configurar uma conexão de mensagens, deduplicação e fila persistente. Reduzir o limite preserva chamadas vivas. Mais de uma simultânea e atendimento recebido ainda dependem de homologação real.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Limite e snapshot persistidos na mesma transação; instance.callsMaxConcurrent e instance.callsConfigVersion são os valores canônicos. Compare a versão com respostas e eventos em trânsito.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallSettingsResult"
                }
              }
            }
          },
          "400": {
            "description": "invalid_calls_max_concurrent (obrigatório, inteiro de 1 a 8), invalid_json ou invalid_body."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind: configuração exclusiva de instâncias calls."
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestInstanceCallSettings",
          "TestCallSettingsDefaultAndLegacyInstances",
          "TestCallSettingsVersionCanReconcileResponsesAndWebhooks",
          "TestCallSettingsWebhookSubscription",
          "TestIncomingPolicySettingsPartialUpdatesAndCAS"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallSettingsRequest"
              },
              "example": {
                "callsMaxConcurrent": 2
              }
            }
          }
        }
      }
    },
    "/v1/instances/{id}/call-settings": {
      "post": {
        "operationId": "adminConfigureInstanceCalls",
        "tags": [
          "Ligações"
        ],
        "summary": "Configurar limite e comportamento das chamadas recebidas da instância",
        "description": "Persiste parcialmente callsMaxConcurrent e/ou incomingCallMode, mesmo desconectada, sem iniciar chamadas ou reiniciar a sessão. Campos omitidos permanecem. expectedCallsConfigVersion opcional exige a versão atual e retorna 409 settings_version_conflict em divergência. Cada POST aceito incrementa callsConfigVersion e grava atomicamente call_settings com limite e modo, mesmo repetindo valores. Alterações de modo valem para novas chamadas. O worker local aplica imediatamente; outro worker aplica na renovação do lease. Rejeições automáticas geram histórico e evento, inclusive quando ocupado, sem consumir uma vaga de atendimento. reject_reply somente solicita resposta ao consumidor: a instância calls não envia texto. A integração deve configurar uma conexão de mensagens, deduplicação e fila persistente. Reduzir o limite preserva chamadas vivas. Mais de uma simultânea e atendimento recebido ainda dependem de homologação real.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "format": "uuid"
            },
            "description": "Identificador devolvido pela API."
          }
        ],
        "responses": {
          "200": {
            "description": "Limite e snapshot persistidos na mesma transação; instance.callsMaxConcurrent e instance.callsConfigVersion são os valores canônicos. Compare a versão com respostas e eventos em trânsito.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CallSettingsResult"
                }
              }
            }
          },
          "400": {
            "description": "invalid_calls_max_concurrent (obrigatório, inteiro de 1 a 8), invalid_json ou invalid_body."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind: configuração exclusiva de instâncias calls."
          },
          "502": {
            "$ref": "#/components/responses/StorageUnavailable"
          },
          "404": {
            "description": "instance_not_found."
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestInstanceCallSettings",
          "TestCallSettingsDefaultAndLegacyInstances",
          "TestCallSettingsVersionCanReconcileResponsesAndWebhooks",
          "TestCallSettingsWebhookSubscription",
          "TestIncomingPolicySettingsPartialUpdatesAndCAS"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallSettingsRequest"
              },
              "example": {
                "callsMaxConcurrent": 2
              }
            }
          }
        }
      }
    },
    "/call/video": {
      "post": {
        "operationId": "callVideo",
        "tags": [
          "Ligações"
        ],
        "summary": "Ligar, aceitar ou desligar o vídeo de uma ligação",
        "description": "Ação de vídeo numa chamada atendida da instância calls. Exige capabilities.calls_video=true. start em chamada de áudio pede vídeo ao contato e fica pending até a resposta; em chamada que já negociou vídeo reabre a câmera. accept responde ao pedido do contato (videoState.requested). stop desliga a câmera deste lado sem encerrar a chamada nem o vídeo do contato. Os quadros trafegam por GET /call/{id}/video. Recurso experimental: o caminho de mídia de vídeo do motor ainda não foi homologado em laboratório.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CallVideoRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estado da chamada após a ação, com videoState.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Call"
                }
              }
            }
          },
          "400": {
            "description": "invalid_call_id, invalid_video_action ou invalid_json.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "call_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou invalid_call_state (chamada não atendida, já encerrada, ou accept sem pedido do contato).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "calls_not_supported: módulo desligado; calls_video_not_supported: vídeo desligado no worker (ATENDROZAP_CALLS_VIDEO_ENABLED) ou motor sem vídeo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "call_failed: o motor recusou a transição.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallVideoRoutes",
          "TestCallRoutesAreGatedByKind",
          "TestCallRoutesMapSessionErrors"
        ]
      }
    },
    "/call/{id}/video": {
      "get": {
        "operationId": "streamCallVideo",
        "tags": [
          "Ligações"
        ],
        "summary": "Abrir ponte WebSocket de vídeo",
        "description": "Upgrade WebSocket. Mensagens binárias nos dois sentidos: uma unidade de acesso H.264 (Annex-B) por mensagem, precedida por cabeçalho de 8 bytes — byte 0 versão (1); byte 1 flags (bit 0 = keyframe, informado na descida); byte 2 orientação da câmera do contato (0..3, descida); byte 3 reservado; bytes 4..7 duração do quadro em microssegundos, big-endian (na subida avança o relógio do fluxo; 0 = passo padrão de 1/30 s). A API não codifica nem decodifica pixels: o cliente usa WebCodecs, ffmpeg ou codec de hardware. Mensagens de texto da API são avisos JSON: {\\\"event\\\":\\\"keyframe\\\"} quando o contato precisa de um IDR no próximo quadro e {\\\"event\\\":\\\"video\\\",\\\"video\\\":{...}} a cada mudança de videoState (o primeiro aviso é o estado atual). Pode ser aberta antes de haver vídeo: assim a ponte não perde o keyframe que abre o fluxo do contato. Quadros enviados com o fluxo fechado são descartados. Perder o socket mantém a chamada e a negociação de vídeo por 30 segundos aguardando reconexão com o mesmo callId; um novo socket de vídeo cancela o prazo, substitui o primeiro (4003) e pede um keyframe. Sem retorno, encerra com hangup/local. Para desligar só a câmera, use POST /call/video com action: stop. Códigos 4000 encerrada, 4001 cabeçalho inválido, 4002 falha de escrita, 4003 substituído. Mesma autenticação e origens da ponte de áudio. Exige capabilities.calls_video=true.",
        "security": [
          {
            "InstanceToken": []
          },
          {
            "InstanceQueryToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "callId retornado pela API."
          }
        ],
        "responses": {
          "101": {
            "description": "WebSocket estabelecido; mensagens binárias H.264 com cabeçalho e avisos JSON em texto."
          },
          "400": {
            "description": "Upgrade WebSocket inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Origem de navegador não autorizada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "call_not_found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "wrong_instance_kind, not_connected, owned_elsewhere ou chamada já encerrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "501": {
            "description": "calls_not_supported: módulo desligado; calls_video_not_supported: vídeo desligado no worker (ATENDROZAP_CALLS_VIDEO_ENABLED) ou motor sem vídeo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestCallVideoRoutes",
          "TestCallRoutesAreGatedByKind"
        ]
      }
    },
    "/call/{id}/recording/video": {
      "get": {
        "operationId": "downloadCallVideoRecording",
        "tags": [
          "Ligações"
        ],
        "summary": "Assistir ou baixar gravação de vídeo",
        "description": "MP4 H.264 1280×360 com atendente à esquerda e contato à direita, áudio AAC estéreo. Gerado após o encerramento quando a captura opcional está habilitada; preserva o WAV independente. Header token obrigatório; query token recusada. Suporta Range e cache privado desabilitado. Somente no worker que armazena o arquivo; faça proxy autenticado no backend consumidor. A rota não altera o estado da chamada nem ocupa uma vaga de ligação.",
        "security": [
          {
            "InstanceToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "description": "callId retornado pela API."
          },
          {
            "name": "Range",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Intervalo HTTP de bytes para reprodução/seek."
          }
        ],
        "responses": {
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "wrong_instance_kind: download disponível apenas em instâncias calls; não exige sessão conectada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          },
          "200": {
            "description": "Gravação pronta.",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "call_not_found ou recording_not_available: inclui vídeo ausente, recording, processing ou failed."
          },
          "206": {
            "description": "Intervalo de bytes da gravação.",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "410": {
            "description": "recording_expired: vídeo fora do prazo de retenção."
          },
          "416": {
            "description": "Intervalo de bytes inválido."
          },
          "503": {
            "description": "recording_unavailable_on_worker ou recording_file_unavailable."
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestVideoRecordingRouteRequiresHeaderCredential",
          "TestCallVideoRecordingFilesArePrivate",
          "TestCallHistoryRoutesArePrivateAndWorkOffline"
        ]
      }
    },
    "/v1/system/status": {
      "get": {
        "operationId": "getSystemStatus",
        "tags": [
          "Diagnóstico"
        ],
        "summary": "Consultar saúde operacional do worker",
        "description": "Leitura administrativa de métricas agregadas, sem instâncias individuais, números/JIDs, mensagens, URLs de webhook, tokens, caminhos ou comandos. HTTP 200 informa que o observador respondeu; consultar status/available de cada bloco. As consultas PostgreSQL têm orçamento de 3 s. Process contém métricas Go/API; host vem de arquivo local produzido pelo coletor no host e inclui idade/validade próprias. Arquivo ausente, inválido ou antigo permanece unavailable/stale. Não aceita destino, URL ou caminho pela requisição. Usar a API central com token de monitoramento para acesso de suporte sem fornecer admintoken de cada servidor.",
        "security": [
          {
            "AdminToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshot agregado; dependências indisponíveis ficam explícitas no corpo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SystemStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        },
        "x-implemented": true,
        "x-contract-tests": [
          "TestSystemStatusRequiresAdminAndIsReadOnly",
          "TestSystemStatusReportsProcessSeparatelyAndNeverFakesHost",
          "TestSystemStatusDatabaseUnavailableAndUnsupportedAreExplicit",
          "TestSystemStatusMarksStaleHostAndSanitizesSnapshot"
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "AdminToken": {
        "type": "apiKey",
        "in": "header",
        "name": "admintoken",
        "description": "ATENDROZAP_ADMIN_TOKEN do servidor. Somente backend administrativo; nunca frontend/documentação."
      },
      "InstanceToken": {
        "type": "apiKey",
        "in": "header",
        "name": "token",
        "description": "instance.token emitido no init/reemissão. Não é o admin token. instancekey/Authorization/query não substituem este header."
      },
      "InstanceQueryToken": {
        "type": "apiKey",
        "in": "query",
        "name": "token",
        "description": "Alternativa exclusiva da ponte WebSocket. Preferir o proxy do console, que mantém a credencial no backend. Não registrar a query."
      }
    },
    "parameters": {
      "RequestId": {
        "name": "X-Request-Id",
        "in": "header",
        "required": false,
        "description": "ASCII visível sem espaços, 1–128 caracteres. Inválido/ausente é substituído por UUID. Ecoado na resposta.",
        "schema": {
          "type": "string",
          "maxLength": 128
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "ASCII visível sem espaços, 1–128. Repetir método, caminho e os mesmos bytes do JSON. 409 em andamento; 422 se mudar a requisição. 504 é guardado e não deve causar reenvio automático.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Falha; usar HTTP status e error. 404 rota inexistente; 405 método inválido com Allow. Ver catálogo no guia de integração.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "unauthorized: header ausente, inválido ou duplicado. Bearer/query/instancekey não substituem admintoken/token.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "StorageUnavailable": {
        "description": "storage_unavailable (Retry-After=5). Algumas rotas também retornam 502 por falha da conexão/mídia; consultar error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "string"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "messageid": {
            "type": "string",
            "description": "ID para reconciliação quando o resultado é ambíguo."
          },
          "messageId": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "provider_code": {
            "type": "integer"
          },
          "error_key": {
            "type": "string"
          },
          "error_source": {
            "type": "string"
          },
          "details": {
            "type": "object"
          },
          "instance": {
            "$ref": "#/components/schemas/Instance"
          }
        },
        "required": [
          "error"
        ]
      },
      "Health": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "alive",
              "ready",
              "not_ready"
            ]
          },
          "reason": {
            "type": "string",
            "enum": [
              "database_unreachable"
            ]
          }
        },
        "required": [
          "status"
        ]
      },
      "Capabilities": {
        "type": "object",
        "properties": {
          "service": {
            "type": "string",
            "enum": [
              "AtendroZAP"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "laboratory"
            ]
          },
          "worker": {
            "type": "string"
          },
          "engine": {
            "type": "object"
          },
          "capabilities": {
            "type": "object",
            "properties": {
              "calls": {
                "type": "boolean",
                "description": "Habilitado neste worker por ATENDROZAP_CALLS_ENABLED; exige instância calls."
              },
              "ptt_transcoding": {
                "type": "boolean",
                "enum": [
                  false
                ]
              },
              "call_history": {
                "type": "boolean"
              },
              "call_recording": {
                "type": "boolean",
                "description": "Gravação automática das chamadas atendidas habilitada neste worker."
              },
              "calls_per_instance_limit": {
                "type": "boolean",
                "description": "Permite configurar callsMaxConcurrent por instância, sem reiniciar a sessão."
              },
              "calls_video": {
                "type": "boolean",
                "description": "Chamadas de vídeo, upgrade no meio da ligação e ponte GET /call/{id}/video habilitados neste worker por ATENDROZAP_CALLS_VIDEO_ENABLED (exige calls). Recurso experimental até a homologação em laboratório."
              },
              "calls_settings_webhook": {
                "type": "boolean",
                "description": "Anuncia call_settings com limite/versionamento em outbox atômica e callsConfigVersion em objetos instance. Exige inscrição explícita em call_settings; connection pode trazer o snapshot opcional em instance."
              },
              "calls_video_recording": {
                "type": "boolean",
                "description": "Captura de vídeo e geração de MP4 lado a lado habilitadas neste worker por ATENDROZAP_CALLS_VIDEO_RECORDING_ENABLED. Opt-in: requer calls_video, call_recording, FFmpeg e ffprobe. Não implica homologação em celulares reais."
              },
              "calls_incoming_policy": {
                "type": "boolean",
                "description": "Permite configurar incomingCallMode, comparar expectedCallsConfigVersion e receber decisões de recusa automática com metadados por chamada. Não garante envio de mensagem pelo consumidor nem homologação de áudio recebido."
              }
            },
            "additionalProperties": {
              "type": "boolean"
            }
          },
          "interactive": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "webhookEvents": {
            "type": "object",
            "properties": {
              "delivered": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "ignored": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "instance_kinds": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "whatsapp",
                "calls"
              ]
            }
          },
          "calls_max_concurrent": {
            "type": "integer",
            "minimum": 0,
            "description": "Padrão do servidor usado na criação e em instâncias antigas sem limite próprio. Consulte instance.callsMaxConcurrent para o limite efetivo."
          },
          "calls_recording_retention_days": {
            "type": "integer",
            "minimum": 0,
            "description": "Retenção das gravações de áudio em dias; 0 desativa exclusão automática do áudio. Vídeo possui prazo independente. Histórico preservado."
          },
          "calls_video_recording_retention_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650,
            "description": "Retenção das gravações MP4 em dias, contados do encerramento da chamada. Padrão 7, independente do áudio. Histórico preservado."
          },
          "calls_max_concurrent_range": {
            "type": "object",
            "properties": {
              "min": {
                "type": "integer",
                "const": 1
              },
              "max": {
                "type": "integer",
                "const": 8
              }
            },
            "required": [
              "min",
              "max"
            ]
          }
        },
        "required": [
          "service",
          "status",
          "capabilities"
        ]
      },
      "Instance": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "systemName": {
            "type": "string"
          },
          "companyId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "disconnected",
              "connecting",
              "connected"
            ]
          },
          "owner": {
            "type": "string"
          },
          "profileName": {
            "type": "string"
          },
          "qrcode": {
            "type": "string",
            "description": "PNG em data URI quando há QR vigente; vazio no restante e nas listagens."
          },
          "paircode": {
            "type": "string"
          },
          "lastDisconnect": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "lastDisconnectReason": {
            "type": "string"
          },
          "disconnectCode": {
            "type": "string"
          },
          "worker": {
            "type": "string"
          },
          "limitEnforcement": {
            "type": "string"
          },
          "limitUntil": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "created": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "updated": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "kind": {
            "type": "string",
            "enum": [
              "whatsapp",
              "calls"
            ]
          },
          "callsMaxConcurrent": {
            "type": "integer",
            "minimum": 1,
            "maximum": 8,
            "description": "Limite próprio de ligações simultâneas da instância calls: voz e vídeo, recebidas e realizadas, incluindo ringing/connecting/active e reservas de discagem. Acima de 1 ainda depende de homologação em chamadas reais."
          },
          "callsConfigVersion": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Versão crescente da configuração de chamadas; presente inclusive 0 em objetos instance de kind=calls. Comparar esta versão entre respostas HTTP e snapshots de webhook para evitar regressões. O campo não pertence às instâncias whatsapp."
          },
          "incomingCallMode": {
            "$ref": "#/components/schemas/IncomingCallMode"
          }
        },
        "required": [
          "id",
          "name",
          "status",
          "qrcode",
          "owner",
          "profileName",
          "kind"
        ]
      },
      "IssuedInstance": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Instance"
          },
          {
            "type": "object",
            "properties": {
              "token": {
                "type": "string",
                "description": "Segredo de instância: guardar no backend. Só criação/reemissão; replay idempotente de init pode repetir por 15 min.",
                "minLength": 64,
                "maxLength": 64
              }
            },
            "required": [
              "token"
            ]
          }
        ]
      },
      "Connection": {
        "type": "object",
        "properties": {
          "connected": {
            "type": "boolean",
            "description": "Socket conectado."
          },
          "loggedIn": {
            "type": "boolean",
            "description": "Credencial de sessão autenticada; usar junto de connected."
          },
          "jid": {
            "type": "string"
          },
          "instance": {
            "$ref": "#/components/schemas/Instance"
          },
          "webhooks": {
            "type": "object",
            "description": "Presente no status, inclui registered e a saúde de entrega quando registrada."
          }
        },
        "required": [
          "connected",
          "loggedIn",
          "jid",
          "instance"
        ]
      },
      "InitRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Obrigatório, até 128 bytes UTF-8, sem controle ou espaços nas extremidades.",
            "minLength": 1,
            "maxLength": 128
          },
          "systemName": {
            "type": "string",
            "description": "Até 128 bytes; recomendado Atendro.",
            "maxLength": 128
          },
          "companyId": {
            "type": "string",
            "description": "Até 128 bytes; vínculo com tenant no consumidor. Filtro de lista, não autorização.",
            "maxLength": 128
          },
          "kind": {
            "type": "string",
            "enum": [
              "whatsapp",
              "calls"
            ],
            "default": "whatsapp",
            "description": "Imutável após criar. calls exige o módulo habilitado e pareamento próprio."
          },
          "callsMaxConcurrent": {
            "type": "integer",
            "minimum": 1,
            "maximum": 8,
            "description": "Limite de ligações simultâneas desta instância calls, incluindo as que estão tocando. Acima de 1 ainda depende de homologação em chamadas reais. Opcional na criação; omitido, persiste o padrão ATENDROZAP_CALLS_MAX_CONCURRENT do servidor. Recusado em kind=whatsapp."
          },
          "incomingCallMode": {
            "allOf": [
              {
                "$ref": "#/components/schemas/IncomingCallMode"
              }
            ],
            "default": "allow",
            "description": "Opcional apenas em kind=calls. Omitido, preserva o comportamento allow."
          }
        },
        "required": [
          "name"
        ]
      },
      "InitResult": {
        "type": "object",
        "properties": {
          "response": {
            "type": "string"
          },
          "connected": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "loggedIn": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "instance": {
            "$ref": "#/components/schemas/IssuedInstance"
          }
        },
        "required": [
          "response",
          "connected",
          "loggedIn",
          "instance"
        ]
      },
      "ConnectRequest": {
        "type": "object",
        "properties": {
          "phone": {
            "type": "string",
            "description": "Opcional. Sem phone usa QR; com phone extrai 8–15 dígitos incluindo DDI e pede código de pareamento."
          }
        }
      },
      "DisconnectResult": {
        "type": "object",
        "properties": {
          "response": {
            "type": "string"
          },
          "unlinked": {
            "type": "boolean",
            "description": "Indica confirmação remota. Credencial local é limpa mesmo se false."
          },
          "instance": {
            "$ref": "#/components/schemas/Instance"
          }
        },
        "required": [
          "response",
          "unlinked",
          "instance"
        ]
      },
      "RestartResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Connection"
          },
          {
            "type": "object",
            "properties": {
              "response": {
                "type": "string"
              }
            },
            "required": [
              "response"
            ]
          }
        ]
      },
      "ResponseMessage": {
        "type": "object",
        "properties": {
          "response": {
            "type": "string"
          }
        },
        "required": [
          "response"
        ]
      },
      "TokenRequest": {
        "type": "object",
        "properties": {
          "graceSeconds": {
            "type": "integer",
            "description": "Prazo de convivência do token anterior; zero revoga imediatamente.",
            "minimum": 0,
            "maximum": 3600,
            "default": 0
          }
        }
      },
      "TokenResult": {
        "type": "object",
        "properties": {
          "response": {
            "type": "string"
          },
          "graceSeconds": {
            "type": "integer"
          },
          "instance": {
            "$ref": "#/components/schemas/IssuedInstance"
          }
        },
        "required": [
          "response",
          "graceSeconds",
          "instance"
        ]
      },
      "SendTextRequest": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
            "minLength": 1
          },
          "replyid": {
            "type": "string",
            "description": "ID de mensagem guardada para citação; desconhecida retorna 422 reply_not_found."
          },
          "delay": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "Espera de digitação em milissegundos; o manager limita a 15000 ms."
          },
          "forward": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "text": {
            "type": "string",
            "description": "UTF-8, não vazio/branco, até 65536 bytes.",
            "minLength": 1,
            "maxLength": 65536
          },
          "linkPreview": {
            "description": "Aceito e ignorado; o serviço não gera prévia de link."
          }
        },
        "required": [
          "number",
          "text"
        ]
      },
      "SendMediaRequest": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
            "minLength": 1
          },
          "replyid": {
            "type": "string",
            "description": "ID de mensagem guardada para citação; desconhecida retorna 422 reply_not_found."
          },
          "delay": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "Espera de digitação em milissegundos; o manager limita a 15000 ms."
          },
          "forward": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "image",
              "video",
              "audio",
              "ptt",
              "document",
              "sticker"
            ]
          },
          "file": {
            "type": "string",
            "description": "Data URI, base64 ou URL permitida por ATENDROZAP_MEDIA_URL_ALLOWLIST. Até 32 MiB decodificados; JSON até 48 MiB.",
            "minLength": 1
          },
          "text": {
            "type": "string",
            "description": "Legenda em UTF-8, até 65536 bytes.",
            "maxLength": 65536
          },
          "docName": {
            "type": "string",
            "description": "Nome-base do documento."
          }
        },
        "required": [
          "number",
          "type",
          "file"
        ]
      },
      "SendContactRequest": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
            "minLength": 1
          },
          "replyid": {
            "type": "string",
            "description": "ID de mensagem guardada para citação; desconhecida retorna 422 reply_not_found."
          },
          "delay": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "Espera de digitação em milissegundos; o manager limita a 15000 ms."
          },
          "forward": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "fullName": {
            "type": "string",
            "description": "Nome do contato sintético/autorizado, 1–128 bytes após trim.",
            "minLength": 1,
            "maxLength": 128
          },
          "phoneNumber": {
            "type": "string",
            "description": "Telefone do contato: 8–15 dígitos com DDI após retirar formatação."
          },
          "organization": {
            "type": "string",
            "description": "Até 128 bytes.",
            "maxLength": 128
          }
        },
        "required": [
          "number",
          "fullName",
          "phoneNumber"
        ]
      },
      "SendLocationRequest": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
            "minLength": 1
          },
          "replyid": {
            "type": "string",
            "description": "ID de mensagem guardada para citação; desconhecida retorna 422 reply_not_found."
          },
          "delay": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "Espera de digitação em milissegundos; o manager limita a 15000 ms."
          },
          "forward": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "latitude": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "longitude": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "name": {
            "type": "string",
            "description": "Até 256 bytes.",
            "maxLength": 256
          },
          "address": {
            "type": "string",
            "description": "Até 512 bytes.",
            "maxLength": 512
          }
        },
        "required": [
          "number",
          "latitude",
          "longitude"
        ]
      },
      "SendMenuRequest": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
            "minLength": 1
          },
          "replyid": {
            "type": "string",
            "description": "ID de mensagem guardada para citação; desconhecida retorna 422 reply_not_found."
          },
          "delay": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "Espera de digitação em milissegundos; o manager limita a 15000 ms."
          },
          "forward": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "button",
              "buttons",
              "list",
              "poll"
            ]
          },
          "text": {
            "type": "string",
            "description": "Até 4096 bytes.",
            "minLength": 1,
            "maxLength": 4096
          },
          "choices": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "label|id|descrição, label\nid ou label; [Seção] nas listas; url:/copy: em botões. call: não suportado."
            },
            "minItems": 1
          },
          "footerText": {
            "type": "string"
          },
          "listButton": {
            "type": "string"
          },
          "selectableCount": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "Só em type=poll; padrão 1."
          },
          "renderMode": {
            "type": "string",
            "enum": [
              "auto",
              "native",
              "poll",
              "text"
            ],
            "default": "auto"
          }
        },
        "required": [
          "number",
          "type",
          "text",
          "choices"
        ]
      },
      "SendResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "messageid": {
            "type": "string"
          },
          "messageId": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix em segundos.",
            "format": "int64"
          }
        },
        "required": [
          "success",
          "messageid",
          "messageId",
          "id",
          "timestamp"
        ]
      },
      "SendMediaResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SendResult"
          },
          {
            "type": "object",
            "properties": {
              "mimetype": {
                "type": "string"
              },
              "ptt": {
                "type": "boolean"
              },
              "note": {
                "type": "string",
                "description": "Explica envio como áudio comum quando PTT não é possível."
              }
            },
            "required": [
              "mimetype",
              "ptt"
            ]
          }
        ]
      },
      "SendMenuResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SendResult"
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string"
              },
              "renderMode": {
                "type": "string",
                "enum": [
                  "auto",
                  "native",
                  "poll",
                  "text"
                ]
              },
              "rendered": {
                "type": "string",
                "enum": [
                  "button",
                  "list",
                  "poll",
                  "text"
                ]
              }
            },
            "required": [
              "type",
              "renderMode",
              "rendered"
            ]
          }
        ]
      },
      "ReactRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          },
          "messageId": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          },
          "number": {
            "type": "string",
            "description": "Ignorado para reação, edição e exclusão; o chat vem da mensagem guardada."
          },
          "text": {
            "type": "string",
            "description": "Um emoji; vazio/ausente remove a reação."
          }
        },
        "anyOf": [
          {
            "required": [
              "id"
            ]
          },
          {
            "required": [
              "messageId"
            ]
          }
        ]
      },
      "DeleteMessageRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          },
          "messageId": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          },
          "number": {
            "type": "string",
            "description": "Ignorado para reação, edição e exclusão; o chat vem da mensagem guardada."
          }
        },
        "anyOf": [
          {
            "required": [
              "id"
            ]
          },
          {
            "required": [
              "messageId"
            ]
          }
        ]
      },
      "EditRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          },
          "messageId": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          },
          "number": {
            "type": "string",
            "description": "Ignorado para reação, edição e exclusão; o chat vem da mensagem guardada."
          },
          "text": {
            "type": "string",
            "description": "Texto/legenda UTF-8, não vazio, até 65536 bytes.",
            "minLength": 1,
            "maxLength": 65536
          }
        },
        "required": [
          "text"
        ],
        "anyOf": [
          {
            "required": [
              "id"
            ]
          },
          {
            "required": [
              "messageId"
            ]
          }
        ]
      },
      "ForwardRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          },
          "messageId": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          },
          "number": {
            "type": "string",
            "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
            "minLength": 1
          },
          "delay": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "Espera de digitação em milissegundos; o manager limita a 15000 ms."
          }
        },
        "required": [
          "number"
        ],
        "anyOf": [
          {
            "required": [
              "id"
            ]
          },
          {
            "required": [
              "messageId"
            ]
          }
        ]
      },
      "ReactResult": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SendResult"
          },
          {
            "type": "object",
            "properties": {
              "reaction": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "emoji": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "sent",
                      "removed"
                    ]
                  }
                },
                "required": [
                  "id",
                  "emoji",
                  "status"
                ]
              }
            },
            "required": [
              "reaction"
            ]
          }
        ]
      },
      "DeleteMessageResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "id": {
            "type": "string"
          },
          "messageid": {
            "type": "string"
          },
          "messageId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "Deleted"
            ]
          },
          "timestamp": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "recorded": {
            "type": "boolean"
          },
          "alreadyDeleted": {
            "type": "boolean"
          }
        },
        "required": [
          "success",
          "id",
          "status",
          "timestamp",
          "recorded"
        ]
      },
      "EditResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "id": {
            "type": "string",
            "description": "owner:id do original."
          },
          "messageid": {
            "type": "string",
            "description": "ID do original."
          },
          "messageId": {
            "type": "string"
          },
          "editId": {
            "type": "string",
            "description": "ID da ação de edição."
          },
          "content": {
            "type": "string"
          },
          "messageType": {
            "type": "string"
          },
          "messageTimestamp": {
            "type": "integer",
            "description": "Unix em milissegundos.",
            "format": "int64"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix em segundos.",
            "format": "int64"
          },
          "status": {
            "type": "string"
          },
          "owner": {
            "type": "string"
          },
          "editCount": {
            "type": "integer"
          },
          "recorded": {
            "type": "boolean",
            "description": "false: WhatsApp aceitou mas a persistência local falhou."
          }
        },
        "required": [
          "success",
          "id",
          "messageid",
          "editId",
          "recorded"
        ]
      },
      "FindMessagesRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          },
          "chatid": {
            "type": "string",
            "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
            "minLength": 1
          },
          "limit": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 200
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "0/ausente usa 100; máximo 200.",
            "default": 100
          },
          "offset": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "Deslocamento da página."
          },
          "includeHistory": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ],
            "default": true
          }
        }
      },
      "LegacyMessage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "owner:messageid."
          },
          "messageid": {
            "type": "string"
          },
          "chatid": {
            "type": "string"
          },
          "sender": {
            "type": "string"
          },
          "sender_pn": {
            "type": "string"
          },
          "senderName": {
            "type": "string"
          },
          "pushName": {
            "type": "string"
          },
          "isGroup": {
            "type": "boolean"
          },
          "fromMe": {
            "type": "boolean"
          },
          "wasSentByApi": {
            "type": "boolean"
          },
          "messageType": {
            "type": "string",
            "description": "Tipo legado PascalCase."
          },
          "type": {
            "type": "string"
          },
          "messageTimestamp": {
            "type": "integer",
            "description": "Unix em milissegundos.",
            "format": "int64"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix em segundos.",
            "format": "int64"
          },
          "status": {
            "type": "string",
            "description": "Pending, Sent, Delivered, Read, Played, Failed, Received ou Deleted."
          },
          "text": {
            "type": "string"
          },
          "content": {
            "type": "object"
          },
          "buttonOrListid": {
            "type": "string"
          },
          "reactions": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "choices": {
            "description": "Opções armazenadas de menus/enquetes; estrutura depende do tipo e pode ser null."
          },
          "fileURL": {
            "type": "string"
          },
          "mediaUrl": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "messageid",
          "chatid",
          "fromMe"
        ]
      },
      "FindMessagesResult": {
        "type": "object",
        "properties": {
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LegacyMessage"
            }
          },
          "returnedMessages": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "hasMore": {
            "type": "boolean"
          },
          "nextOffset": {
            "type": "integer"
          }
        },
        "required": [
          "messages",
          "returnedMessages",
          "limit",
          "offset",
          "hasMore"
        ]
      },
      "MessageStatus": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "Estado interno, em minúsculas: sending, unknown, failed, sent, delivered, read, played ou received."
          },
          "failure": {
            "type": "string"
          },
          "fromMe": {
            "type": "boolean"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix em segundos.",
            "format": "int64"
          },
          "deliveredAt": {
            "type": [
              "integer",
              "null"
            ]
          },
          "readAt": {
            "type": [
              "integer",
              "null"
            ]
          },
          "playedAt": {
            "type": [
              "integer",
              "null"
            ]
          },
          "revokedAt": {
            "type": [
              "integer",
              "null"
            ]
          },
          "deletedForMeAt": {
            "type": [
              "integer",
              "null"
            ]
          },
          "editedAt": {
            "type": [
              "integer",
              "null"
            ]
          },
          "editCount": {
            "type": "integer"
          },
          "reactions": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object"
            }
          }
        },
        "required": [
          "id",
          "status",
          "failure",
          "fromMe",
          "timestamp"
        ]
      },
      "StoredMessage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "chatid": {
            "type": "string"
          },
          "fromMe": {
            "type": "boolean"
          },
          "status": {
            "type": "string"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix em segundos.",
            "format": "int64"
          }
        },
        "description": "Projeção interna session.DescribeMessage; campos de conteúdo variam com o tipo. Para o formato legado use /message/find."
      },
      "ListMessagesResult": {
        "type": "object",
        "properties": {
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StoredMessage"
            }
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "required": [
          "messages",
          "hasMore"
        ]
      },
      "DownloadRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
            "minLength": 1
          }
        },
        "required": [
          "id"
        ]
      },
      "DownloadResult": {
        "type": "object",
        "properties": {
          "fileURL": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "mimetype": {
            "type": "string"
          },
          "mimeType": {
            "type": "string"
          },
          "fileName": {
            "type": "string"
          },
          "size": {
            "type": "integer"
          },
          "expiresAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "messageid": {
            "type": "string"
          }
        },
        "required": [
          "fileURL",
          "url",
          "mimetype",
          "mimeType",
          "fileName",
          "size",
          "expiresAt",
          "messageid"
        ]
      },
      "MarkReadRequest": {
        "type": "object",
        "properties": {
          "id": {
            "oneOf": [
              {
                "type": "string",
                "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
                "minLength": 1
              },
              {
                "type": "array",
                "items": {
                  "type": "string",
                  "description": "ID da mensagem guardada nesta instância. Nos corpos aceita também owner:id.",
                  "minLength": 1
                },
                "minItems": 1,
                "maxItems": 1000
              }
            ]
          }
        },
        "required": [
          "id"
        ]
      },
      "MarkReadResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "marked": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "count": {
            "type": "integer"
          }
        },
        "required": [
          "success",
          "marked",
          "count"
        ]
      },
      "ChatReadRequest": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
            "minLength": 1
          },
          "read": {
            "type": "boolean",
            "description": "Ausente equivale a true; false não marca como não lido e retorna marked=0 com note.",
            "default": true
          }
        },
        "required": [
          "number"
        ]
      },
      "ChatReadResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "marked": {
            "type": "integer"
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "success",
          "marked"
        ]
      },
      "CheckRequest": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "Um telefone com DDI."
          },
          "numbers": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "maxItems": 50
              }
            ]
          }
        },
        "anyOf": [
          {
            "required": [
              "number"
            ]
          },
          {
            "required": [
              "numbers"
            ]
          }
        ]
      },
      "NumberCheck": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "exists": {
            "type": "boolean"
          },
          "numberExists": {
            "type": "boolean"
          },
          "jid": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "exists": {
                "type": "boolean"
              },
              "jid": {
                "type": "string"
              }
            }
          }
        },
        "required": [
          "query",
          "exists",
          "numberExists",
          "jid",
          "data"
        ]
      },
      "DetailsRequest": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
            "minLength": 1
          }
        },
        "required": [
          "number"
        ]
      },
      "ChatDetails": {
        "type": "object",
        "properties": {
          "jid": {
            "type": "string"
          },
          "exists": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "pushName": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "verifiedName": {
            "type": "string"
          },
          "isBusiness": {
            "type": "boolean"
          },
          "profilePicUrl": {
            "type": "string"
          },
          "profilePictureUrl": {
            "type": "string"
          },
          "imagePreview": {
            "type": "string"
          },
          "pictureId": {
            "type": "string"
          },
          "imageState": {
            "type": "string"
          }
        },
        "required": [
          "jid",
          "exists",
          "profilePicUrl"
        ]
      },
      "FindChatsRequest": {
        "type": "object",
        "properties": {
          "limit": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 5000
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "0/ausente retorna até 5000.",
            "default": 5000
          },
          "offset": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "string",
                "description": "Inteiro em formato decimal.",
                "pattern": "^\\d+$"
              }
            ],
            "description": "Deslocamento da página."
          },
          "wa_isGroup": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "includeLeft": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "Chat": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "wa_chatid": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "wa_name": {
            "type": "string"
          },
          "wa_contactName": {
            "type": "string"
          },
          "wa_isGroup": {
            "type": "boolean"
          },
          "wa_unreadCount": {
            "type": "integer"
          },
          "wa_archived": {
            "type": "boolean"
          },
          "wa_lastMsgTimestamp": {
            "type": "integer",
            "description": "Unix em segundos.",
            "format": "int64"
          },
          "wa_lastMessageTime": {
            "type": "integer",
            "description": "Unix em segundos.",
            "format": "int64"
          },
          "owner": {
            "type": "string"
          },
          "phone": {
            "type": "string",
            "description": "Vazio para grupo ou LID sem telefone conhecido."
          },
          "pictureId": {
            "type": "string"
          },
          "wa_isGroup_announce": {
            "type": "boolean"
          },
          "participantCount": {
            "type": "integer"
          },
          "topic": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "wa_chatid",
          "wa_isGroup",
          "wa_lastMsgTimestamp",
          "wa_lastMessageTime"
        ]
      },
      "FindChatsResult": {
        "type": "object",
        "properties": {
          "chats": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Chat"
            }
          },
          "hasMore": {
            "type": "boolean"
          },
          "pagination": {
            "type": "object",
            "properties": {
              "limit": {
                "type": "integer"
              },
              "offset": {
                "type": "integer"
              },
              "returned": {
                "type": "integer"
              }
            },
            "required": [
              "limit",
              "offset",
              "returned"
            ]
          },
          "nextOffset": {
            "type": "integer"
          }
        },
        "required": [
          "chats",
          "hasMore",
          "pagination"
        ]
      },
      "GroupParticipant": {
        "type": "object",
        "properties": {
          "JID": {
            "type": "string"
          },
          "PhoneNumber": {
            "type": "string"
          },
          "LID": {
            "type": "string"
          },
          "IsAdmin": {
            "type": "boolean"
          },
          "IsSuperAdmin": {
            "type": "boolean"
          },
          "DisplayName": {
            "type": "string"
          },
          "Error": {
            "type": "integer",
            "description": "Código por participante; 0 indica ausência de erro registrado."
          }
        },
        "required": [
          "JID",
          "IsAdmin",
          "IsSuperAdmin",
          "DisplayName",
          "Error"
        ]
      },
      "Group": {
        "type": "object",
        "properties": {
          "JID": {
            "type": "string"
          },
          "Name": {
            "type": "string"
          },
          "Topic": {
            "type": "string"
          },
          "OwnerJID": {
            "type": "string"
          },
          "OwnerPN": {
            "type": "string"
          },
          "IsLocked": {
            "type": "boolean"
          },
          "IsAnnounce": {
            "type": "boolean"
          },
          "AddressingMode": {
            "type": "string"
          },
          "ParticipantCount": {
            "type": "integer"
          },
          "Participants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GroupParticipant"
            }
          },
          "invite_link": {
            "type": "string",
            "description": "Vazio se não solicitado ou sem permissão de admin."
          },
          "PictureID": {
            "type": "string"
          },
          "lastMessageAt": {
            "type": "integer",
            "description": "Unix em segundos.",
            "format": "int64"
          },
          "syncedAt": {
            "type": "integer",
            "description": "Unix em segundos.",
            "format": "int64"
          },
          "left": {
            "type": "boolean"
          },
          "GroupCreated": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          }
        },
        "required": [
          "JID",
          "Name",
          "ParticipantCount",
          "invite_link"
        ]
      },
      "GroupInfoRequest": {
        "type": "object",
        "properties": {
          "groupjid": {
            "type": "string",
            "description": "Identificador do grupo terminado em @g.us.",
            "minLength": 1
          },
          "force": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "getInviteLink": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "getRequestsParticipants": {
            "description": "Aceito e ignorado."
          }
        },
        "required": [
          "groupjid"
        ]
      },
      "CreateGroupRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "participants": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
              "minLength": 1
            },
            "maxItems": 50,
            "minItems": 1
          }
        },
        "required": [
          "name",
          "participants"
        ]
      },
      "GroupParticipantsRequest": {
        "type": "object",
        "properties": {
          "groupjid": {
            "type": "string",
            "description": "Identificador do grupo terminado em @g.us.",
            "minLength": 1
          },
          "action": {
            "type": "string",
            "enum": [
              "add",
              "remove",
              "promote",
              "demote"
            ]
          },
          "participants": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Dígitos com DDI (8–15) ou identificador @s.whatsapp.net, @g.us ou @lid. Nunca inferir telefone de um LID.",
              "minLength": 1
            },
            "minItems": 1
          }
        },
        "required": [
          "groupjid",
          "action",
          "participants"
        ]
      },
      "GroupParticipantsResult": {
        "type": "object",
        "properties": {
          "groupUpdated": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "JID": {
                  "type": "string"
                },
                "Error": {
                  "type": "integer"
                }
              },
              "required": [
                "JID",
                "Error"
              ]
            }
          },
          "needs_refresh": {
            "type": "boolean",
            "enum": [
              true
            ]
          }
        },
        "required": [
          "groupUpdated",
          "needs_refresh"
        ]
      },
      "GroupNameRequest": {
        "type": "object",
        "properties": {
          "groupjid": {
            "type": "string",
            "description": "Identificador do grupo terminado em @g.us.",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          }
        },
        "required": [
          "groupjid",
          "name"
        ]
      },
      "GroupImageRequest": {
        "type": "object",
        "properties": {
          "groupjid": {
            "type": "string",
            "description": "Identificador do grupo terminado em @g.us.",
            "minLength": 1
          },
          "image": {
            "type": "string",
            "description": "Data URI/base64/URL permitida (JPEG, PNG, GIF; até 8 MiB), ou remove/delete. Convertida para JPEG até 640×640.",
            "minLength": 1
          }
        },
        "required": [
          "groupjid",
          "image"
        ]
      },
      "GroupUpdateResult": {
        "type": "object",
        "properties": {
          "response": {
            "type": "string"
          },
          "needs_refresh": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "pictureId": {
            "type": "string",
            "description": "Presente na atualização de imagem."
          }
        },
        "required": [
          "response",
          "needs_refresh"
        ]
      },
      "ProxyRequest": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "custom",
              "none",
              "internal"
            ]
          },
          "proxy_url": {
            "type": "string",
            "description": "Obrigatória em custom; http/https/socks5/socks5h; sondada antes da gravação.",
            "writeOnly": true
          },
          "confirm_no_proxy": {
            "type": "boolean",
            "description": "Obrigatório true em mode=none."
          }
        },
        "required": [
          "mode"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "mode": {
                  "const": "custom"
                }
              }
            },
            "then": {
              "required": [
                "proxy_url"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "mode": {
                  "const": "none"
                }
              }
            },
            "then": {
              "required": [
                "confirm_no_proxy"
              ],
              "properties": {
                "confirm_no_proxy": {
                  "const": true
                }
              }
            }
          }
        ]
      },
      "Proxy": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "custom",
              "none"
            ]
          },
          "effective_mode": {
            "type": "string",
            "enum": [
              "custom",
              "none"
            ]
          },
          "effective_detail": {
            "type": "string",
            "enum": [
              "direct",
              "instance",
              "sealed"
            ]
          },
          "fallback": {
            "type": "object",
            "properties": {
              "active": {
                "type": "boolean",
                "enum": [
                  false
                ]
              },
              "reason": {
                "type": "string"
              },
              "since": {
                "type": "integer"
              }
            }
          },
          "proxy_url": {
            "type": "string",
            "description": "Credenciais redigidas."
          },
          "proxy_fallback": {
            "type": "string",
            "enum": [
              "never"
            ]
          },
          "managed": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "last_test_at": {
            "type": "integer",
            "description": "Unix em milissegundos."
          },
          "last_test_error": {
            "type": "string"
          },
          "validation_error": {
            "type": "boolean"
          }
        },
        "required": [
          "mode",
          "effective_mode",
          "fallback",
          "proxy_url"
        ]
      },
      "ProxyResult": {
        "type": "object",
        "properties": {
          "details": {
            "type": "string"
          },
          "proxy": {
            "$ref": "#/components/schemas/Proxy"
          },
          "restart_requested": {
            "type": "boolean"
          }
        },
        "required": [
          "details",
          "proxy",
          "restart_requested"
        ]
      },
      "WebhookRequest": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "add",
              "update",
              "delete",
              "inherit"
            ],
            "default": "add"
          },
          "enabled": {
            "type": "boolean",
            "default": true
          },
          "url": {
            "type": "string",
            "description": "HTTPS público, sem credenciais/redirects; exceções de laboratório na allowlist.",
            "maxLength": 2048
          },
          "events": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "Entregues: connection, messages, messages_update, messages_edit, groups, limits, undecryptable, call e call_settings. call_settings exige inscrição explícita, independentemente de call. Instâncias calls filtram mensagens, recibos, edições, grupos e undecryptable, inclusive no backlog. Nomes de compatibilidade documentados são aceitos e ignorados."
          },
          "excludeMessages": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "wasSentByApi, wasNotSentByApi, fromMeYes, fromMeNo, isGroupYes, isGroupNo."
          },
          "addUrlEvents": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Deve ser false."
          },
          "addUrlTypesMessages": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Deve ser false."
          },
          "secret": {
            "type": "string",
            "description": "Segredo de assinatura do webhook; até 256 ASCII sem espaços. Nunca é devolvido.",
            "maxLength": 256,
            "writeOnly": true
          }
        },
        "anyOf": [
          {
            "required": [
              "action"
            ],
            "properties": {
              "action": {
                "enum": [
                  "delete",
                  "inherit"
                ]
              }
            }
          },
          {
            "required": [
              "url",
              "events"
            ]
          }
        ]
      },
      "DeliveryStatus": {
        "type": "object",
        "properties": {
          "consecutiveFailures": {
            "type": "integer"
          },
          "lastStatus": {
            "type": "integer"
          },
          "lastError": {
            "type": "string"
          },
          "paused": {
            "type": "boolean"
          },
          "pausedUntil": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "lastDeliveredAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "pending": {
            "type": "integer"
          },
          "dead": {
            "type": "integer"
          },
          "oldestPendingSeconds": {
            "type": "integer"
          },
          "statsError": {
            "type": "boolean"
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "registered": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "enabled": {
            "type": "boolean"
          },
          "excludeMessages": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "hasSecret": {
            "type": "boolean"
          },
          "secretSealed": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "deliveryStatus": {
            "$ref": "#/components/schemas/DeliveryStatus"
          },
          "ignoredEvents": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "webhooks": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "inheritedGlobal": {
            "type": "boolean",
            "description": "Indica que a inscrição segue o webhook global do servidor."
          }
        },
        "required": [
          "registered"
        ]
      },
      "WebhookWriteResult": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/Webhook"
          },
          {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean",
                "enum": [
                  true
                ]
              },
              "deleted": {
                "type": "boolean",
                "enum": [
                  true
                ]
              }
            },
            "required": [
              "success",
              "deleted"
            ]
          }
        ]
      },
      "WebhookErrors": {
        "type": "object",
        "properties": {
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "Falhas recentes do worker, sem payload."
            }
          },
          "worker": {
            "type": "string"
          },
          "lastStatus": {
            "type": "integer"
          },
          "lastError": {
            "type": "string"
          },
          "consecutiveFailures": {
            "type": "integer"
          }
        },
        "required": [
          "errors",
          "worker"
        ]
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "seq": {
            "type": "integer"
          },
          "type": {
            "type": "string"
          },
          "payload": {
            "type": "object",
            "description": "Evento interno; o envelope HTTP entregue ao consumidor é uma projeção. Ver EVENTS.md."
          },
          "createdAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "attempts": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "delivered",
              "dead"
            ]
          },
          "deliveredAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "deadAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "lastAttemptAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "lastStatus": {
            "type": "integer"
          },
          "lastError": {
            "type": "string"
          },
          "nextAttemptAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "seq",
          "type",
          "payload",
          "createdAt",
          "attempts",
          "status"
        ]
      },
      "EventsResult": {
        "type": "object",
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "events"
        ]
      },
      "ReplayResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "event": {
            "$ref": "#/components/schemas/Event"
          }
        },
        "required": [
          "success",
          "event"
        ]
      },
      "AdminRestartResult": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "worker": {
            "type": "string"
          }
        },
        "required": [
          "message",
          "worker"
        ]
      },
      "GlobalWebhookRequest": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "add",
              "update",
              "delete"
            ],
            "default": "add"
          },
          "enabled": {
            "type": "boolean",
            "default": true
          },
          "url": {
            "type": "string",
            "description": "HTTPS público, sem credenciais/redirects; exceções de laboratório na allowlist.",
            "maxLength": 2048
          },
          "events": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "Entregues: connection, messages, messages_update, messages_edit, groups, limits, undecryptable, call e call_settings. call_settings exige inscrição explícita, independentemente de call. Instâncias calls filtram mensagens, recibos, edições, grupos e undecryptable, inclusive no backlog. Nomes de compatibilidade documentados são aceitos e ignorados."
          },
          "excludeMessages": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "wasSentByApi, wasNotSentByApi, fromMeYes, fromMeNo, isGroupYes, isGroupNo."
          },
          "addUrlEvents": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Deve ser false."
          },
          "addUrlTypesMessages": {
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "true",
                  "false",
                  "1",
                  "0",
                  ""
                ]
              },
              {
                "type": "integer",
                "enum": [
                  0,
                  1
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Deve ser false."
          },
          "secret": {
            "type": "string",
            "description": "Segredo de assinatura do webhook; até 256 ASCII sem espaços. Nunca é devolvido.",
            "maxLength": 256,
            "writeOnly": true
          }
        },
        "anyOf": [
          {
            "required": [
              "action"
            ],
            "properties": {
              "action": {
                "const": "delete"
              }
            }
          },
          {
            "required": [
              "url",
              "events"
            ]
          }
        ]
      },
      "GlobalWebhook": {
        "type": "object",
        "properties": {
          "registered": {
            "type": "boolean"
          },
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "enabled": {
            "type": "boolean"
          },
          "excludeMessages": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "hasSecret": {
            "type": "boolean"
          },
          "secretSealed": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "description": "RFC 3339.",
            "format": "date-time"
          },
          "ignoredEvents": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "scope": {
            "type": "string",
            "const": "server"
          }
        },
        "required": [
          "registered",
          "scope"
        ]
      },
      "MakeCallRequest": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "minLength": 1,
            "description": "Telefone com DDI (formatação removida pela API) ou JID de conversa direta. Resolve as duas formas do nono dígito brasileiro."
          },
          "video": {
            "type": "boolean",
            "default": false,
            "description": "Inicia uma chamada de vídeo: a oferta anuncia vídeo e o envio da câmera abre quando a mídia começa. Exige capabilities.calls_video=true; caso contrário 501 calls_video_not_supported."
          }
        },
        "required": [
          "number"
        ]
      },
      "CallActionRequest": {
        "type": "object",
        "properties": {
          "callId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "callId"
        ]
      },
      "Call": {
        "type": "object",
        "properties": {
          "callId": {
            "type": "string"
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ]
          },
          "number": {
            "type": "string",
            "description": "Identidade telefônica canônica, quando conhecida."
          },
          "jid": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "ringing",
              "connecting",
              "active",
              "ended"
            ]
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "answeredAt": {
            "type": "string",
            "format": "date-time",
            "description": "Momento do aceite remoto ou do atendimento local; não depende do primeiro áudio."
          },
          "endedAt": {
            "type": "string",
            "format": "date-time"
          },
          "endReason": {
            "type": "string",
            "description": "hangup, rejected, ring_timeout, closed, unknown ou motivo do motor. Um terminate remoto sem motivo explícito (ausente, vazio ou só espaços) é hangup/remote: solicitação remota de encerramento, sem comprovar ação humana. Motivos explícitos são preservados; callbacks genéricos sem motivo continuam unknown. O primeiro motivo fica no histórico; registros antigos não são reclassificados."
          },
          "endedBy": {
            "type": "string",
            "enum": [
              "local",
              "remote"
            ]
          },
          "answered": {
            "type": "boolean",
            "description": "Verdadeiro a partir do aceite, mesmo antes de o áudio iniciar."
          },
          "mediaStartedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Momento em que o motor confirmou mídia recebida."
          },
          "durationSeconds": {
            "type": "number",
            "minimum": 0,
            "description": "Tempo entre atendimento e encerramento; zero para chamadas sem atendimento ou ainda em curso."
          },
          "recording": {
            "$ref": "#/components/schemas/CallRecording"
          },
          "video": {
            "type": "boolean",
            "description": "Verdadeiro quando a chamada é ou foi de vídeo (negociado em qualquer direção em algum momento). Permanece no histórico."
          },
          "videoState": {
            "$ref": "#/components/schemas/CallVideoState"
          },
          "videoRecording": {
            "$ref": "#/components/schemas/CallVideoRecording"
          },
          "incomingCallMode": {
            "$ref": "#/components/schemas/IncomingCallMode"
          },
          "callsConfigVersion": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Versão da política congelada na chegada da chamada recebida. Não é seq do evento; mudanças de configuração posteriores não alteram esta decisão."
          },
          "rejectionSource": {
            "type": "string",
            "enum": [
              "policy",
              "busy",
              "manual"
            ],
            "description": "Origem de uma recusa confirmada: política automática, ocupação ou operador. Não confundir com timeout, desligamento remoto ou atendimento em outro dispositivo."
          },
          "autoReplyRequested": {
            "type": "boolean",
            "description": "Verdadeiro somente após recusa confirmada por política reject_reply. O consumidor enfileira o texto uma única vez por instância/chamada; este campo não comprova envio da resposta."
          }
        },
        "required": [
          "callId",
          "direction",
          "number",
          "status",
          "startedAt",
          "video"
        ]
      },
      "ActiveCalls": {
        "type": "object",
        "properties": {
          "calls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Call"
            }
          }
        },
        "required": [
          "calls"
        ]
      },
      "CallRecording": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "not_recorded",
              "recording",
              "ready",
              "failed",
              "expired"
            ]
          },
          "contentType": {
            "type": "string",
            "enum": [
              "audio/wav"
            ]
          },
          "bytes": {
            "type": "integer"
          },
          "durationSeconds": {
            "type": "number"
          },
          "downloadPath": {
            "type": "string",
            "description": "Caminho relativo autenticado com header token; somente quando ready."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "failureReason": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CallHistory": {
        "type": "object",
        "required": [
          "calls",
          "hasMore",
          "nextCursor"
        ],
        "properties": {
          "calls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Call"
            }
          },
          "hasMore": {
            "type": "boolean"
          },
          "nextCursor": {
            "type": "string",
            "description": "Usar como before na próxima página; vazio quando não há mais resultados."
          }
        },
        "additionalProperties": false
      },
      "CallSettingsRequest": {
        "type": "object",
        "properties": {
          "callsMaxConcurrent": {
            "type": "integer",
            "minimum": 1,
            "maximum": 8,
            "description": "Limite próprio de ligações simultâneas da instância calls: voz e vídeo, recebidas e realizadas, incluindo ringing/connecting/active e reservas de discagem. Acima de 1 ainda depende de homologação em chamadas reais."
          },
          "incomingCallMode": {
            "$ref": "#/components/schemas/IncomingCallMode"
          },
          "expectedCallsConfigVersion": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Comparação condicional opcional. Se diferente da versão salva, retorna 409 settings_version_conflict sem alterar a instância. Enviar junto a pelo menos um campo de configuração."
          }
        },
        "anyOf": [
          {
            "required": [
              "callsMaxConcurrent"
            ]
          },
          {
            "required": [
              "incomingCallMode"
            ]
          }
        ],
        "description": "Atualização parcial: informe callsMaxConcurrent e/ou incomingCallMode. Campos omitidos são preservados. Cada atualização aceita incrementa callsConfigVersion. Alterar o modo afeta apenas novas chamadas."
      },
      "CallSettingsResult": {
        "type": "object",
        "properties": {
          "instance": {
            "$ref": "#/components/schemas/Instance"
          }
        },
        "required": [
          "instance"
        ]
      },
      "CallVideoState": {
        "type": "object",
        "description": "Estado vivo do vídeo; presente apenas enquanto a chamada não terminou. Os campos sending/receiving refletem o fluxo negociado, não quadros efetivamente trafegando.",
        "required": [
          "active",
          "sending",
          "receiving",
          "requested",
          "pending",
          "orientation"
        ],
        "properties": {
          "active": {
            "type": "boolean",
            "description": "Vídeo ligado em pelo menos uma direção."
          },
          "sending": {
            "type": "boolean",
            "description": "O fluxo de vídeo deste lado está aberto: quadros enviados pela ponte de vídeo chegam ao contato."
          },
          "receiving": {
            "type": "boolean",
            "description": "A câmera do contato está ligada."
          },
          "requested": {
            "type": "boolean",
            "description": "O contato pediu para adicionar vídeo e aguarda action=accept. O WhatsApp retira o pedido sozinho se ninguém responder."
          },
          "pending": {
            "type": "boolean",
            "description": "Este lado pediu vídeo (action=start em chamada de áudio) e o contato ainda não respondeu."
          },
          "orientation": {
            "type": "integer",
            "minimum": 0,
            "maximum": 3,
            "description": "Orientação da câmera do contato em quartos de volta no sentido horário; gire os quadros recebidos por orientation×90° para exibir em pé."
          }
        },
        "additionalProperties": false
      },
      "CallVideoRequest": {
        "type": "object",
        "required": [
          "callId",
          "action"
        ],
        "properties": {
          "callId": {
            "type": "string",
            "minLength": 1
          },
          "action": {
            "type": "string",
            "enum": [
              "start",
              "accept",
              "stop"
            ],
            "description": "start liga a câmera deste lado: em chamada só de áudio vira pedido ao contato (pending até a resposta); em chamada que já negociou vídeo apenas reabre o fluxo. accept aceita o pedido do contato (videoState.requested). stop desliga a câmera deste lado ou retira o pedido pendente; o vídeo do contato e o áudio continuam."
          }
        },
        "additionalProperties": false
      },
      "CallSettingsEventData": {
        "type": "object",
        "description": "Snapshot em data do webhook EventType=call_settings; assinado no envelope existente e entregue somente a inscritos. Cada POST call-settings aceito grava este snapshot e a configuração atomicamente, inclusive desconectado e sem mudança de valor. A configuração inicial é consultada no status. O evento connection usa campos opcionais em instance, não este data. Inclui incomingCallMode; limite e modo formam um único snapshot versionado.",
        "properties": {
          "kind": {
            "type": "string",
            "const": "calls"
          },
          "callsMaxConcurrent": {
            "type": "integer",
            "minimum": 1,
            "maximum": 8,
            "description": "Limite compartilhado de voz/vídeo e chamadas recebidas/realizadas. Redução não encerra chamadas vivas."
          },
          "callsConfigVersion": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "description": "Versão crescente por instância, incrementada a cada POST aceito; independente de seq do envelope. Retries do mesmo evento preservam a versão."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Horário UTC da atualização em RFC3339Nano. Comparar versões, não timestamps, para aplicar snapshots."
          },
          "incomingCallMode": {
            "$ref": "#/components/schemas/IncomingCallMode"
          }
        },
        "required": [
          "kind",
          "callsMaxConcurrent",
          "callsConfigVersion",
          "updatedAt",
          "incomingCallMode"
        ],
        "additionalProperties": true,
        "example": {
          "kind": "calls",
          "callsMaxConcurrent": 2,
          "callsConfigVersion": 3,
          "updatedAt": "2026-09-19T15:00:00.123456789Z",
          "incomingCallMode": "allow"
        }
      },
      "CallVideoRecording": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "recording",
              "processing",
              "ready",
              "failed",
              "expired"
            ]
          },
          "contentType": {
            "type": "string",
            "enum": [
              "video/mp4"
            ]
          },
          "bytes": {
            "type": "integer"
          },
          "durationSeconds": {
            "type": "number"
          },
          "downloadPath": {
            "type": "string",
            "description": "Caminho relativo GET /call/{id}/recording/video, autenticado somente pelo header token; presente apenas quando ready."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "failureReason": {
            "type": "string"
          }
        },
        "additionalProperties": false,
        "description": "Gravação de vídeo independente do WAV. Campo opcional, presente somente após começar a captura de vídeo. processing indica composição do MP4 em fila após a chamada; não muda o estado ou a ocupação de ligações. O primeiro resultado terminal é preservado."
      },
      "CallVideoRecordingEventData": {
        "type": "object",
        "description": "Subevento no data do envelope existente EventType=call, entregue a inscritos em call. video_recording_ready/video_recording_failed atualizam apenas o vídeo: não são ended, não liberam vaga e não substituem recording do WAV. Deduplicar por eventId e ordenar pelo seq do envelope. Pode chegar antes ou depois do ended devido à entrega assíncrona; não há data.seq do ciclo da chamada.",
        "required": [
          "callId",
          "event",
          "videoRecording",
          "timestamp"
        ],
        "properties": {
          "callId": {
            "type": "string"
          },
          "event": {
            "type": "string",
            "enum": [
              "video_recording_ready",
              "video_recording_failed"
            ]
          },
          "videoRecording": {
            "type": "object",
            "required": [
              "status",
              "contentType",
              "durationMs",
              "bytes",
              "failureReason"
            ],
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "ready",
                  "failed"
                ]
              },
              "contentType": {
                "type": "string",
                "const": "video/mp4"
              },
              "durationMs": {
                "type": "integer"
              },
              "bytes": {
                "type": "integer"
              },
              "failureReason": {
                "type": "string"
              }
            },
            "additionalProperties": false
          },
          "timestamp": {
            "type": "integer",
            "description": "Horário do registro do evento em segundos Unix."
          }
        },
        "additionalProperties": false
      },
      "HostHealthCPU": {
        "additionalProperties": true,
        "properties": {
          "ioWaitPercent": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "logicalCPUs": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "stealPercent": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "usagePercent": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "logicalCPUs",
          "usagePercent",
          "ioWaitPercent",
          "stealPercent"
        ],
        "type": "object"
      },
      "HostHealthDirectory": {
        "additionalProperties": true,
        "properties": {
          "auxiliaryBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "auxiliaryFiles": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "bytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "complete": {
            "description": "false identifica varredura parcial/interrompida: os bytes/arquivos observados são um limite inferior, não um total completo.",
            "type": "boolean"
          },
          "compressedBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "compressedFiles": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "files": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "incompleteBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "incompleteFiles": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "latestAgeSeconds": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "oldestAgeSeconds": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "rawBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "rawFiles": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "complete",
          "bytes",
          "files",
          "rawBytes",
          "rawFiles",
          "compressedBytes",
          "compressedFiles",
          "incompleteBytes",
          "incompleteFiles",
          "auxiliaryBytes",
          "auxiliaryFiles",
          "oldestAgeSeconds",
          "latestAgeSeconds"
        ],
        "type": "object"
      },
      "HostHealthDiskIO": {
        "additionalProperties": true,
        "properties": {
          "busyPercent": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "inFlight": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "readBytesPerSecond": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "readsPerSecond": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "scope": {
            "enum": [
              "root_device"
            ],
            "type": "string"
          },
          "writeBytesPerSecond": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "writesPerSecond": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "scope",
          "inFlight",
          "readBytesPerSecond",
          "writeBytesPerSecond",
          "readsPerSecond",
          "writesPerSecond",
          "busyPercent"
        ],
        "type": "object"
      },
      "HostHealthDocker": {
        "additionalProperties": true,
        "properties": {
          "available": {
            "type": "boolean"
          },
          "services": {
            "anyOf": [
              {
                "additionalProperties": {
                  "$ref": "#/components/schemas/HostHealthService"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "available",
          "services"
        ],
        "type": "object"
      },
      "HostHealthFilesystem": {
        "additionalProperties": true,
        "properties": {
          "availableBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "availablePercent": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "freeBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "inodesFree": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "inodesTotal": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "inodesUsedPercent": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "reservedBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "totalBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "usedBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "usedPercent": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "totalBytes",
          "freeBytes",
          "availableBytes",
          "reservedBytes",
          "usedBytes",
          "usedPercent",
          "availablePercent",
          "inodesTotal",
          "inodesFree",
          "inodesUsedPercent"
        ],
        "type": "object"
      },
      "HostHealthLoad": {
        "additionalProperties": true,
        "properties": {
          "fifteen": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "fifteenPerCPU": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "five": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "fivePerCPU": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "one": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "onePerCPU": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "one",
          "five",
          "fifteen",
          "onePerCPU",
          "fivePerCPU",
          "fifteenPerCPU"
        ],
        "type": "object"
      },
      "HostHealthMemory": {
        "additionalProperties": true,
        "properties": {
          "availableBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "totalBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "usedBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "usedPercent": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "totalBytes",
          "availableBytes",
          "usedBytes",
          "usedPercent"
        ],
        "type": "object"
      },
      "HostHealthNetwork": {
        "additionalProperties": true,
        "properties": {
          "interfaces": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "receivedBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "receivedBytesPerSecond": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "scope": {
            "description": "Agrega interfaces não loopback, incluindo interfaces virtuais; não equivale ao tráfego externo faturado pelo provedor.",
            "enum": [
              "all_non_loopback"
            ],
            "type": "string"
          },
          "transmittedBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "transmittedBytesPerSecond": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "scope",
          "interfaces",
          "receivedBytes",
          "transmittedBytes",
          "receivedBytesPerSecond",
          "transmittedBytesPerSecond"
        ],
        "type": "object"
      },
      "HostHealthOperations": {
        "additionalProperties": true,
        "properties": {
          "backupVerification": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HostHealthVerification"
              },
              {
                "type": "null"
              }
            ]
          },
          "docker": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HostHealthDocker"
              },
              {
                "type": "null"
              }
            ]
          },
          "storage": {
            "anyOf": [
              {
                "additionalProperties": {
                  "$ref": "#/components/schemas/HostHealthDirectory"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "docker",
          "storage",
          "backupVerification"
        ],
        "type": "object"
      },
      "HostHealthResult": {
        "additionalProperties": true,
        "properties": {
          "ageSeconds": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "errors": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ]
          },
          "snapshot": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HostHealthSnapshot"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "enum": [
              "ok",
              "degraded",
              "stale",
              "unavailable"
            ],
            "type": "string"
          }
        },
        "required": [
          "status",
          "ageSeconds",
          "snapshot",
          "errors"
        ],
        "type": "object"
      },
      "HostHealthService": {
        "additionalProperties": true,
        "properties": {
          "containers": {
            "minimum": 0,
            "type": "integer"
          },
          "health": {
            "enum": [
              "unknown",
              "none",
              "healthy",
              "starting",
              "unhealthy"
            ],
            "type": "string"
          },
          "oomKilled": {
            "minimum": 0,
            "type": "integer"
          },
          "restarting": {
            "minimum": 0,
            "type": "integer"
          },
          "restarts": {
            "minimum": 0,
            "type": "integer"
          },
          "running": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "containers",
          "running",
          "restarting",
          "oomKilled",
          "restarts",
          "health"
        ],
        "type": "object"
      },
      "HostHealthSnapshot": {
        "additionalProperties": true,
        "properties": {
          "cpu": {
            "$ref": "#/components/schemas/HostHealthCPU"
          },
          "diskIO": {
            "$ref": "#/components/schemas/HostHealthDiskIO"
          },
          "errors": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ]
          },
          "intervalSeconds": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "load": {
            "$ref": "#/components/schemas/HostHealthLoad"
          },
          "memory": {
            "$ref": "#/components/schemas/HostHealthMemory"
          },
          "network": {
            "$ref": "#/components/schemas/HostHealthNetwork"
          },
          "operations": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HostHealthOperations"
              },
              {
                "type": "null"
              }
            ]
          },
          "rootFilesystem": {
            "$ref": "#/components/schemas/HostHealthFilesystem"
          },
          "sampledAt": {
            "format": "date-time",
            "type": "string"
          },
          "schemaVersion": {
            "const": 1,
            "minimum": 0,
            "type": "integer"
          },
          "source": {
            "enum": [
              "host"
            ],
            "type": "string"
          },
          "swap": {
            "$ref": "#/components/schemas/HostHealthSwap"
          },
          "uptimeSeconds": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "validForSeconds": {
            "maximum": 3600,
            "minimum": 1,
            "type": "integer"
          }
        },
        "required": [
          "schemaVersion",
          "source",
          "sampledAt",
          "validForSeconds",
          "intervalSeconds",
          "uptimeSeconds",
          "cpu",
          "memory",
          "swap",
          "load",
          "rootFilesystem",
          "network",
          "diskIO",
          "errors"
        ],
        "type": "object"
      },
      "HostHealthSwap": {
        "additionalProperties": true,
        "properties": {
          "freeBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "totalBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "usedBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "usedPercent": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "totalBytes",
          "freeBytes",
          "usedBytes",
          "usedPercent"
        ],
        "type": "object"
      },
      "HostHealthVerification": {
        "additionalProperties": true,
        "properties": {
          "ageSeconds": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "verified": {
            "description": "Indica marcador local de pg_verifybackup bem-sucedido. Não comprova sozinho teste de restauração, cópia externa ou continuidade de toda a cadeia PITR.",
            "type": "boolean"
          },
          "verifiedAt": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "verified",
          "verifiedAt",
          "ageSeconds"
        ],
        "type": "object"
      },
      "SystemStatus": {
        "additionalProperties": true,
        "properties": {
          "database": {
            "$ref": "#/components/schemas/SystemStatusDatabase"
          },
          "host": {
            "$ref": "#/components/schemas/HostHealthResult"
          },
          "process": {
            "$ref": "#/components/schemas/SystemStatusProcess",
            "description": "Processo Go/API: heap e runtimeSys não são RAM usada da VPS; gomaxprocs não mede núcleos físicos nem CPU do host."
          },
          "sampledAt": {
            "description": "Instante UTC da amostragem do worker. O host tem sampledAt e idade próprios.",
            "format": "date-time",
            "type": "string"
          },
          "schemaVersion": {
            "const": 1,
            "minimum": 0,
            "type": "integer"
          },
          "status": {
            "description": "HTTP 200 significa que o observador respondeu. Verificar available/status em cada bloco; valores indisponíveis não representam consumo zero.",
            "enum": [
              "ok",
              "degraded"
            ],
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "workerId": {
            "pattern": "^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$",
            "type": "string"
          },
          "workload": {
            "$ref": "#/components/schemas/SystemStatusWorkload"
          }
        },
        "required": [
          "schemaVersion",
          "sampledAt",
          "status",
          "workerId",
          "process",
          "database",
          "workload",
          "host"
        ],
        "type": "object"
      },
      "SystemStatusArchiver": {
        "additionalProperties": true,
        "properties": {
          "archiveTimeoutSeconds": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "archivedCount": {
            "minimum": 0,
            "type": "integer"
          },
          "available": {
            "type": "boolean"
          },
          "backlogErrorCode": {
            "enum": [
              "archiver_backlog_unavailable"
            ],
            "type": "string"
          },
          "commandSource": {
            "description": "Origem enumerada de pg_settings.source; nunca o comando, caminho ou conteúdo da configuração.",
            "enum": [
              "unknown",
              "default",
              "environment variable",
              "configuration file",
              "command line",
              "global",
              "database",
              "user",
              "database user",
              "client",
              "override",
              "interactive",
              "test",
              "session"
            ],
            "type": "string"
          },
          "errorCode": {
            "enum": [
              "database_unavailable",
              "archiver_stats_unavailable",
              "monitoring_unsupported"
            ],
            "type": "string"
          },
          "failedCount": {
            "description": "Falhas acumuladas desde statsResetAt; não indica, isoladamente, falha atual.",
            "minimum": 0,
            "type": "integer"
          },
          "lastArchivedAt": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "lastFailedAt": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "mode": {
            "enum": [
              "off",
              "on",
              "always"
            ],
            "type": "string"
          },
          "readyFiles": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "segmentBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "statsResetAt": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "description": "blocked: última falha posterior ao último sucesso e readyFiles>0. failedCount é cumulativo e sozinho não dispara alarme. disabled corresponde a archive_mode=off. degraded indica backlog não consultável.",
            "enum": [
              "ok",
              "disabled",
              "degraded",
              "blocked",
              "unavailable"
            ],
            "type": "string"
          },
          "timeoutSource": {
            "description": "Origem enumerada de pg_settings.source; nunca o comando, caminho ou conteúdo da configuração.",
            "enum": [
              "unknown",
              "default",
              "environment variable",
              "configuration file",
              "command line",
              "global",
              "database",
              "user",
              "database user",
              "client",
              "override",
              "interactive",
              "test",
              "session"
            ],
            "type": "string"
          },
          "walBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "available",
          "status",
          "archivedCount",
          "failedCount"
        ],
        "type": "object"
      },
      "SystemStatusCallCounts": {
        "additionalProperties": true,
        "properties": {
          "active": {
            "minimum": 0,
            "type": "integer"
          },
          "connecting": {
            "minimum": 0,
            "type": "integer"
          },
          "live": {
            "description": "Chamadas persistidas abertas com lease vigente deste worker. Exclui snapshots cujo lease expirou ou mudou; não mede fluxo RTP/saúde de mídia.",
            "minimum": 0,
            "type": "integer"
          },
          "persistedOpen": {
            "minimum": 0,
            "type": "integer"
          },
          "ringing": {
            "minimum": 0,
            "type": "integer"
          },
          "scope": {
            "enum": [
              "worker"
            ],
            "type": "string"
          },
          "source": {
            "enum": [
              "database_snapshot"
            ],
            "type": "string"
          },
          "stale": {
            "minimum": 0,
            "type": "integer"
          },
          "video": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "source",
          "scope",
          "persistedOpen",
          "live",
          "stale",
          "ringing",
          "connecting",
          "active",
          "video"
        ],
        "type": "object"
      },
      "SystemStatusDatabase": {
        "additionalProperties": true,
        "properties": {
          "archiver": {
            "$ref": "#/components/schemas/SystemStatusArchiver"
          },
          "available": {
            "type": "boolean"
          },
          "errorCode": {
            "enum": [
              "database_unavailable",
              "database_size_unavailable",
              "monitoring_unsupported"
            ],
            "type": "string"
          },
          "pool": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SystemStatusPool"
              },
              {
                "type": "null"
              }
            ]
          },
          "sizeBytes": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "available",
          "archiver"
        ],
        "type": "object"
      },
      "SystemStatusInstanceCounts": {
        "additionalProperties": true,
        "properties": {
          "callSlotsConfigured": {
            "description": "Soma dos limites de instâncias calls; valores herdados usam o padrão deste worker. Não é capacidade física medida.",
            "minimum": 0,
            "type": "integer"
          },
          "callSlotsOwned": {
            "description": "Soma dos limites das instâncias calls sob lease vigente deste worker.",
            "minimum": 0,
            "type": "integer"
          },
          "calls": {
            "$ref": "#/components/schemas/SystemStatusInstanceState"
          },
          "ownedByWorker": {
            "description": "Leases deste worker ainda não expirados.",
            "minimum": 0,
            "type": "integer"
          },
          "scope": {
            "enum": [
              "database"
            ],
            "type": "string"
          },
          "staleConnected": {
            "description": "Status persistido connected sem lease vigente. Os totais por estado são snapshots persistidos, não sondas da conexão WhatsApp.",
            "minimum": 0,
            "type": "integer"
          },
          "total": {
            "description": "Instâncias não excluídas neste banco. Bancos compartilhados entre workers duplicam esse total: não somar os nós sem considerar o escopo.",
            "minimum": 0,
            "type": "integer"
          },
          "whatsapp": {
            "$ref": "#/components/schemas/SystemStatusInstanceState"
          },
          "workerSessionLimit": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "scope",
          "total",
          "whatsapp",
          "calls",
          "ownedByWorker",
          "staleConnected",
          "callSlotsConfigured",
          "callSlotsOwned"
        ],
        "type": "object"
      },
      "SystemStatusInstanceState": {
        "additionalProperties": true,
        "properties": {
          "connected": {
            "minimum": 0,
            "type": "integer"
          },
          "connecting": {
            "minimum": 0,
            "type": "integer"
          },
          "disconnected": {
            "minimum": 0,
            "type": "integer"
          },
          "total": {
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "total",
          "connected",
          "connecting",
          "disconnected"
        ],
        "type": "object"
      },
      "SystemStatusPool": {
        "additionalProperties": true,
        "properties": {
          "idle": {
            "minimum": 0,
            "type": "integer"
          },
          "inUse": {
            "minimum": 0,
            "type": "integer"
          },
          "maxIdleClosed": {
            "minimum": 0,
            "type": "integer"
          },
          "maxLifetimeClosed": {
            "minimum": 0,
            "type": "integer"
          },
          "maxOpenConnections": {
            "minimum": 0,
            "type": "integer"
          },
          "openConnections": {
            "minimum": 0,
            "type": "integer"
          },
          "waitCount": {
            "minimum": 0,
            "type": "integer"
          },
          "waitDurationSeconds": {
            "minimum": 0,
            "type": "number"
          }
        },
        "required": [
          "maxOpenConnections",
          "openConnections",
          "inUse",
          "idle",
          "waitCount",
          "waitDurationSeconds",
          "maxIdleClosed",
          "maxLifetimeClosed"
        ],
        "type": "object"
      },
      "SystemStatusProcess": {
        "additionalProperties": true,
        "properties": {
          "goVersion": {
            "type": "string"
          },
          "gomaxprocs": {
            "minimum": 0,
            "type": "integer"
          },
          "goroutines": {
            "minimum": 0,
            "type": "integer"
          },
          "heapAllocBytes": {
            "minimum": 0,
            "type": "integer"
          },
          "heapInuseBytes": {
            "minimum": 0,
            "type": "integer"
          },
          "runtimeSysBytes": {
            "minimum": 0,
            "type": "integer"
          },
          "startedAt": {
            "format": "date-time",
            "type": "string"
          },
          "uptimeSeconds": {
            "minimum": 0,
            "type": "number"
          }
        },
        "required": [
          "startedAt",
          "uptimeSeconds",
          "goVersion",
          "gomaxprocs",
          "goroutines",
          "heapAllocBytes",
          "heapInuseBytes",
          "runtimeSysBytes"
        ],
        "type": "object"
      },
      "SystemStatusWebhookCounts": {
        "additionalProperties": true,
        "properties": {
          "dead": {
            "description": "Eventos mortos de instâncias não excluídas, inclusive se o webhook foi desabilitado.",
            "minimum": 0,
            "type": "integer"
          },
          "enabledDestinations": {
            "minimum": 0,
            "type": "integer"
          },
          "failingDestinations": {
            "minimum": 0,
            "type": "integer"
          },
          "oldestPendingAgeSeconds": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "pausedDestinations": {
            "minimum": 0,
            "type": "integer"
          },
          "pending": {
            "description": "Eventos sem entrega nem dead_at, posteriores ao start_seq, com webhook habilitado e instância não excluída. Inclui destinos temporariamente pausados.",
            "minimum": 0,
            "type": "integer"
          },
          "retriedPending": {
            "description": "Eventos elegíveis pendentes com attempts>0; não é contador histórico de todas as falhas.",
            "minimum": 0,
            "type": "integer"
          },
          "scope": {
            "enum": [
              "database"
            ],
            "type": "string"
          }
        },
        "required": [
          "scope",
          "pending",
          "dead",
          "retriedPending",
          "enabledDestinations",
          "failingDestinations",
          "pausedDestinations"
        ],
        "type": "object"
      },
      "SystemStatusWorkload": {
        "additionalProperties": true,
        "properties": {
          "available": {
            "type": "boolean"
          },
          "calls": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SystemStatusCallCounts"
              },
              {
                "type": "null"
              }
            ]
          },
          "errorCode": {
            "enum": [
              "database_unavailable",
              "workload_unavailable",
              "monitoring_unsupported"
            ],
            "type": "string"
          },
          "instances": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SystemStatusInstanceCounts"
              },
              {
                "type": "null"
              }
            ]
          },
          "webhooks": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SystemStatusWebhookCounts"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "available"
        ],
        "type": "object"
      },
      "IncomingCallMode": {
        "type": "string",
        "enum": [
          "allow",
          "reject",
          "reject_reply"
        ],
        "description": "Comportamento para novas chamadas recebidas: allow permite atendimento humano; reject recusa no servidor; reject_reply recusa e solicita ao consumidor resposta por uma conexão de mensagens vinculada. Não atende automaticamente. O envio do texto é independente da recusa."
      }
    }
  }
}
