{
  "openapi": "3.1.0",
  "info": {
    "title": "API Tem Empresas",
    "version": "1.0.0",
    "summary": "Integração de parceiros com a plataforma de benefício-saúde Tem Empresas.",
    "description": "API para parceiros integrarem-se à Tem Empresas: logon e onboarding embarcados do\nbeneficiário e gestão de dependentes com validação de elegibilidade.\n\n**Autenticação.** Cada parceiro recebe `client_id` e `client_secret` e troca por um\ntoken de curta duração em `/api/public/parceiro/oauth/token`. O token carrega escopos;\ncada operação exige o escopo indicado na sua descrição.\n\n**Ambientes.** Homologação para testes com dados fictícios e produção para dados reais.\nO `client_id` é distinto por ambiente.\n\n**Erros.** Sempre no formato `{ sucesso: false, codigo, mensagem }`. Trate pelo `codigo`,\nque é estável; a `mensagem` é amigável e pode ser exibida ao usuário final.\n\n**Dados de saúde.** Respostas de questionário e informações clínicas nunca trafegam\nnesta API nem em parâmetros de URL.",
    "contact": {
      "name": "Integrações Tem Empresas",
      "email": "integracoes@temempresas.com",
      "url": "https://temempresas.com/desenvolvedores"
    }
  },
  "servers": [
    {
      "url": "https://temempresas.com",
      "description": "Produção"
    },
    {
      "url": "https://tem-empresas.lovable.app",
      "description": "Homologação"
    }
  ],
  "tags": [
    {
      "name": "Autenticação",
      "description": "Emissão do token de integração do parceiro (OAuth2 client credentials). Todos os endpoints de parceiro exigem o token no header `Authorization: Bearer`."
    },
    {
      "name": "Jornada embarcada",
      "description": "Abertura das telas da Tem Empresas dentro do aplicativo do parceiro (logon, dados de contato e questionário de saúde) via token de lançamento."
    },
    {
      "name": "Vidas e dependentes",
      "description": "Inclusão e exclusão de dependentes com checagem automática das regras de elegibilidade do contrato."
    },
    {
      "name": "Arquivos",
      "description": "Entrega de documentos por link temporário de uso único."
    },
    {
      "name": "Rotinas internas",
      "description": "Endpoints acionados apenas pelo agendador da própria plataforma. Documentados para transparência; não são abertos a parceiros."
    },
    {
      "name": "Roadmap",
      "description": "Operações já especificadas, ainda não disponíveis para consumo."
    }
  ],
  "security": [
    {
      "parceiroOAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "parceiroOAuth": {
        "type": "oauth2",
        "description": "Token do parceiro obtido por client credentials.",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "/api/public/parceiro/oauth/token",
            "scopes": {
              "embed:launch": "Abrir as telas embarcadas da Tem Empresas.",
              "beneficiario:status": "Consultar pendências de onboarding do beneficiário.",
              "vida:dependente:incluir": "Incluir dependente.",
              "vida:dependente:excluir": "Excluir dependente."
            }
          }
        }
      },
      "cronSecret": {
        "type": "apiKey",
        "in": "header",
        "name": "x-cron-secret",
        "description": "Segredo do agendador interno. Não disponível a parceiros."
      }
    },
    "schemas": {
      "Erro": {
        "type": "object",
        "required": [
          "sucesso",
          "codigo",
          "mensagem"
        ],
        "properties": {
          "sucesso": {
            "type": "boolean",
            "const": false
          },
          "codigo": {
            "type": "string",
            "description": "Código estável do erro.",
            "enum": [
              "AUTH_CREDENCIAL_INVALIDA",
              "AUTH_TOKEN_EXPIRADO",
              "AUTH_ESCOPO_INSUFICIENTE",
              "LAUNCH_TOKEN_INVALIDO",
              "TITULAR_NAO_ENCONTRADO",
              "TITULAR_INATIVO",
              "CONTRATO_SEM_VIGENCIA",
              "DEP_CPF_JA_ATIVO",
              "DEP_BLOQUEIO_REINCLUSAO",
              "DEP_PERMANENCIA_MINIMA",
              "DEP_IDADE_LIMITE",
              "DEP_PARENTESCO_NAO_ELEGIVEL",
              "PRODUTO_SEM_DEPENDENTE",
              "DADOS_INVALIDOS",
              "LIMITE_EXCEDIDO",
              "ERRO_INTERNO"
            ]
          },
          "mensagem": {
            "type": "string",
            "description": "Mensagem amigável, exibível ao usuário."
          },
          "campos": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Detalhe por campo quando `codigo` é DADOS_INVALIDOS."
          }
        }
      },
      "Token": {
        "type": "object",
        "required": [
          "access_token",
          "token_type",
          "expires_in"
        ],
        "properties": {
          "access_token": {
            "type": "string"
          },
          "token_type": {
            "type": "string",
            "const": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "example": 600
          },
          "scope": {
            "type": "string",
            "example": "embed:launch vida:dependente:incluir"
          }
        }
      },
      "LaunchResposta": {
        "type": "object",
        "required": [
          "url",
          "expires_in"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endereço a abrir na WebView. Uso único.",
            "example": "https://temempresas.com/embed/tem-saude?lt=eyJhbGciOi..."
          },
          "expires_in": {
            "type": "integer",
            "example": 300
          }
        }
      },
      "StatusBeneficiario": {
        "type": "object",
        "required": [
          "encontrado",
          "acesso_ativo",
          "contato_completo",
          "questionario_completo"
        ],
        "properties": {
          "encontrado": {
            "type": "boolean"
          },
          "acesso_ativo": {
            "type": "boolean",
            "description": "Beneficiário já ativou o acesso (CPF + senha)."
          },
          "contato_completo": {
            "type": "boolean",
            "description": "E-mail e celular cadastrados."
          },
          "questionario_completo": {
            "type": "boolean",
            "description": "Questionário de saúde do ciclo vigente concluído."
          },
          "pendencias": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "acesso",
                "contato",
                "questionario",
                "termos"
              ]
            }
          }
        }
      },
      "DependenteEntrada": {
        "type": "object",
        "required": [
          "cpf_titular",
          "cpf",
          "nome",
          "data_nascimento",
          "parentesco"
        ],
        "properties": {
          "cpf_titular": {
            "type": "string",
            "example": "84752390990",
            "description": "Somente dígitos."
          },
          "cpf": {
            "type": "string",
            "example": "39218477014"
          },
          "nome": {
            "type": "string",
            "maxLength": 120
          },
          "data_nascimento": {
            "type": "string",
            "format": "date",
            "example": "2010-04-22"
          },
          "parentesco": {
            "type": "string",
            "enum": [
              "conjuge",
              "companheiro",
              "filho",
              "enteado",
              "menor_guarda",
              "pai",
              "mae",
              "outro"
            ]
          },
          "sexo": {
            "type": "string",
            "enum": [
              "F",
              "M",
              "NI"
            ]
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "celular": {
            "type": "string",
            "example": "5511999998888"
          },
          "comprovacao_universitario": {
            "type": "boolean",
            "description": "Informe true quando houver comprovação válida de curso superior."
          }
        }
      },
      "DependenteCriado": {
        "type": "object",
        "required": [
          "sucesso",
          "vida_id",
          "matricula",
          "vigencia_inicio"
        ],
        "properties": {
          "sucesso": {
            "type": "boolean",
            "const": true
          },
          "vida_id": {
            "type": "string",
            "format": "uuid"
          },
          "matricula": {
            "type": "string",
            "example": "2607000040000007266"
          },
          "vigencia_inicio": {
            "type": "string",
            "format": "date",
            "example": "2026-09-01"
          },
          "alerta": {
            "type": "string",
            "description": "Observação não impeditiva (ex.: validade da comprovação)."
          }
        }
      },
      "ExclusaoEntrada": {
        "type": "object",
        "required": [
          "cpf",
          "motivo"
        ],
        "properties": {
          "cpf": {
            "type": "string",
            "example": "39218477014"
          },
          "motivo": {
            "type": "string",
            "enum": [
              "pedido_titular",
              "idade_limite",
              "perda_vinculo",
              "obito",
              "outro"
            ]
          },
          "data_saida": {
            "type": "string",
            "format": "date"
          },
          "observacao": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "ExclusaoResposta": {
        "type": "object",
        "required": [
          "sucesso",
          "vida_id",
          "data_saida"
        ],
        "properties": {
          "sucesso": {
            "type": "boolean",
            "const": true
          },
          "vida_id": {
            "type": "string",
            "format": "uuid"
          },
          "data_saida": {
            "type": "string",
            "format": "date"
          },
          "bloqueio_reinclusao_ate": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        }
      }
    }
  },
  "paths": {
    "/api/public/parceiro/oauth/token": {
      "post": {
        "tags": [
          "Autenticação"
        ],
        "summary": "Emitir token de integração",
        "description": "Troca `client_id` + `client_secret` por um token Bearer de 10 minutos. Envie no corpo em `application/x-www-form-urlencoded`, no padrão OAuth2.",
        "operationId": "emitirToken",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type",
                  "client_id",
                  "client_secret"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "const": "client_credentials"
                  },
                  "client_id": {
                    "type": "string"
                  },
                  "client_secret": {
                    "type": "string"
                  },
                  "scope": {
                    "type": "string",
                    "description": "Escopos desejados, separados por espaço."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token emitido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Token"
                }
              }
            }
          },
          "401": {
            "description": "Credenciais inválidas.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "AUTH_CREDENCIAL_INVALIDA": {
                    "summary": "AUTH_CREDENCIAL_INVALIDA",
                    "value": {
                      "sucesso": false,
                      "codigo": "AUTH_CREDENCIAL_INVALIDA",
                      "mensagem": "Credenciais do parceiro inválidas ou aplicação desativada."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Muitas emissões em sequência.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "LIMITE_EXCEDIDO": {
                    "summary": "LIMITE_EXCEDIDO",
                    "value": {
                      "sucesso": false,
                      "codigo": "LIMITE_EXCEDIDO",
                      "mensagem": "Muitas requisições em sequência. Tente novamente em instantes."
                    }
                  }
                }
              }
            }
          }
        },
        "x-status": "planejado"
      }
    },
    "/api/public/parceiro/embed/launch": {
      "post": {
        "tags": [
          "Jornada embarcada"
        ],
        "summary": "Gerar link das telas embarcadas",
        "description": "Escopo: `embed:launch`.\n\nDevolve uma URL de uso único (5 minutos) para abrir em WebView. A Tem Empresas\nconduz o beneficiário pelas etapas pendentes — logon/ativação por CPF, dados de\ncontato e questionário de saúde — pulando o que já estiver cumprido.\n\nAo final, redirecionamos para o `deep_link` informado (que precisa estar cadastrado\nna aplicação do parceiro) acrescentando `status`, `external_id` e `state`.\n`status=ok` autoriza o app a logar o beneficiário na sua home. Nenhum dado de saúde\nvai na URL de retorno.",
        "operationId": "gerarLaunch",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "deep_link"
                ],
                "properties": {
                  "deep_link": {
                    "type": "string",
                    "format": "uri",
                    "example": "temsaude://onboarding/retorno"
                  },
                  "cpf": {
                    "type": "string",
                    "description": "Opcional: pré-preenche a identificação.",
                    "example": "84752390990"
                  },
                  "state": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Devolvido intacto no retorno."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Link gerado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LaunchResposta"
                }
              }
            }
          },
          "400": {
            "description": "Deep link não cadastrado ou corpo inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "DADOS_INVALIDOS": {
                    "summary": "DADOS_INVALIDOS",
                    "value": {
                      "sucesso": false,
                      "codigo": "DADOS_INVALIDOS",
                      "mensagem": "Alguns campos estão incompletos ou inválidos."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Token ausente ou expirado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "AUTH_TOKEN_EXPIRADO": {
                    "summary": "AUTH_TOKEN_EXPIRADO",
                    "value": {
                      "sucesso": false,
                      "codigo": "AUTH_TOKEN_EXPIRADO",
                      "mensagem": "Sua sessão de integração expirou. Solicite um novo token."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Escopo `embed:launch` ausente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "AUTH_ESCOPO_INSUFICIENTE": {
                    "summary": "AUTH_ESCOPO_INSUFICIENTE",
                    "value": {
                      "sucesso": false,
                      "codigo": "AUTH_ESCOPO_INSUFICIENTE",
                      "mensagem": "Esta aplicação não tem permissão para executar esta operação."
                    }
                  }
                }
              }
            }
          }
        },
        "x-status": "planejado"
      }
    },
    "/api/public/parceiro/beneficiario/status": {
      "get": {
        "tags": [
          "Jornada embarcada"
        ],
        "summary": "Consultar pendências de onboarding",
        "description": "Escopo: `beneficiario:status`. Informa se o beneficiário já ativou o acesso, já preencheu contato e já concluiu o questionário do ciclo vigente — para o app decidir se precisa abrir a WebView. Não devolve dado clínico.",
        "operationId": "statusBeneficiario",
        "parameters": [
          {
            "name": "cpf",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "84752390990"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Situação do beneficiário.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusBeneficiario"
                }
              }
            }
          },
          "403": {
            "description": "Escopo ausente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "AUTH_ESCOPO_INSUFICIENTE": {
                    "summary": "AUTH_ESCOPO_INSUFICIENTE",
                    "value": {
                      "sucesso": false,
                      "codigo": "AUTH_ESCOPO_INSUFICIENTE",
                      "mensagem": "Esta aplicação não tem permissão para executar esta operação."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Limite por CPF (anti-enumeração).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "LIMITE_EXCEDIDO": {
                    "summary": "LIMITE_EXCEDIDO",
                    "value": {
                      "sucesso": false,
                      "codigo": "LIMITE_EXCEDIDO",
                      "mensagem": "Muitas requisições em sequência. Tente novamente em instantes."
                    }
                  }
                }
              }
            }
          }
        },
        "x-status": "planejado"
      }
    },
    "/api/public/parceiro/vidas/dependente": {
      "post": {
        "tags": [
          "Vidas e dependentes"
        ],
        "summary": "Incluir dependente",
        "description": "Escopo: `vida:dependente:incluir`.\n\nAntes de criar a vida, a Tem Empresas aplica as regras de elegibilidade do contrato:\nparentesco permitido, idade limite (21 anos, ou 24 com comprovação de universitário),\npermanência mínima e bloqueio anti-carrossel de reinclusão.\n\nQuando aprovado, a vida é criada e o envio à operadora é enfileirado automaticamente.\nQuando reprovado, devolvemos o código do erro e a mensagem amigável correspondente.",
        "operationId": "incluirDependente",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DependenteEntrada"
              },
              "example": {
                "cpf_titular": "84752390990",
                "cpf": "39218477014",
                "nome": "Ana Beatriz Souza",
                "data_nascimento": "2010-04-22",
                "parentesco": "filho",
                "sexo": "F"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Dependente incluído.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DependenteCriado"
                }
              }
            }
          },
          "400": {
            "description": "Corpo inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "DADOS_INVALIDOS": {
                    "summary": "DADOS_INVALIDOS",
                    "value": {
                      "sucesso": false,
                      "codigo": "DADOS_INVALIDOS",
                      "mensagem": "Alguns campos estão incompletos ou inválidos."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Titular não localizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "TITULAR_NAO_ENCONTRADO": {
                    "summary": "TITULAR_NAO_ENCONTRADO",
                    "value": {
                      "sucesso": false,
                      "codigo": "TITULAR_NAO_ENCONTRADO",
                      "mensagem": "Não encontramos um titular ativo com este CPF."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "CPF já ativo no contrato.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "DEP_CPF_JA_ATIVO": {
                    "summary": "DEP_CPF_JA_ATIVO",
                    "value": {
                      "sucesso": false,
                      "codigo": "DEP_CPF_JA_ATIVO",
                      "mensagem": "Este CPF já está ativo neste contrato."
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Regra de elegibilidade não atendida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "TITULAR_INATIVO": {
                    "summary": "TITULAR_INATIVO",
                    "value": {
                      "sucesso": false,
                      "codigo": "TITULAR_INATIVO",
                      "mensagem": "O titular está inativo e não pode incluir dependentes."
                    }
                  },
                  "CONTRATO_SEM_VIGENCIA": {
                    "summary": "CONTRATO_SEM_VIGENCIA",
                    "value": {
                      "sucesso": false,
                      "codigo": "CONTRATO_SEM_VIGENCIA",
                      "mensagem": "O contrato da empresa não está em vigência."
                    }
                  },
                  "DEP_IDADE_LIMITE": {
                    "summary": "DEP_IDADE_LIMITE",
                    "value": {
                      "sucesso": false,
                      "codigo": "DEP_IDADE_LIMITE",
                      "mensagem": "Dependente acima da idade limite. Filhos maiores só entram com comprovação de universitário."
                    }
                  },
                  "DEP_BLOQUEIO_REINCLUSAO": {
                    "summary": "DEP_BLOQUEIO_REINCLUSAO",
                    "value": {
                      "sucesso": false,
                      "codigo": "DEP_BLOQUEIO_REINCLUSAO",
                      "mensagem": "Este dependente saiu recentemente e só pode voltar após o prazo de carência."
                    }
                  },
                  "DEP_PARENTESCO_NAO_ELEGIVEL": {
                    "summary": "DEP_PARENTESCO_NAO_ELEGIVEL",
                    "value": {
                      "sucesso": false,
                      "codigo": "DEP_PARENTESCO_NAO_ELEGIVEL",
                      "mensagem": "Este grau de parentesco não é elegível no contrato da empresa."
                    }
                  },
                  "PRODUTO_SEM_DEPENDENTE": {
                    "summary": "PRODUTO_SEM_DEPENDENTE",
                    "value": {
                      "sucesso": false,
                      "codigo": "PRODUTO_SEM_DEPENDENTE",
                      "mensagem": "O produto contratado não prevê inclusão de dependentes."
                    }
                  }
                }
              }
            }
          }
        },
        "x-status": "planejado"
      }
    },
    "/api/public/parceiro/vidas/dependente/exclusao": {
      "post": {
        "tags": [
          "Vidas e dependentes"
        ],
        "summary": "Excluir dependente",
        "description": "Escopo: `vida:dependente:excluir`. Registra a saída com o motivo informado, aplica a permanência mínima do contrato e devolve, quando houver, a data até a qual a reinclusão fica bloqueada.",
        "operationId": "excluirDependente",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExclusaoEntrada"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saída registrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExclusaoResposta"
                }
              }
            }
          },
          "404": {
            "description": "Dependente não localizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "TITULAR_NAO_ENCONTRADO": {
                    "summary": "TITULAR_NAO_ENCONTRADO",
                    "value": {
                      "sucesso": false,
                      "codigo": "TITULAR_NAO_ENCONTRADO",
                      "mensagem": "Não encontramos um titular ativo com este CPF."
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Regra de permanência não atendida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "examples": {
                  "DEP_PERMANENCIA_MINIMA": {
                    "summary": "DEP_PERMANENCIA_MINIMA",
                    "value": {
                      "sucesso": false,
                      "codigo": "DEP_PERMANENCIA_MINIMA",
                      "mensagem": "O dependente precisa cumprir a permanência mínima antes desta alteração."
                    }
                  },
                  "CONTRATO_SEM_VIGENCIA": {
                    "summary": "CONTRATO_SEM_VIGENCIA",
                    "value": {
                      "sucesso": false,
                      "codigo": "CONTRATO_SEM_VIGENCIA",
                      "mensagem": "O contrato da empresa não está em vigência."
                    }
                  }
                }
              }
            }
          }
        },
        "x-status": "planejado"
      }
    },
    "/api/public/arquivo/{token}": {
      "get": {
        "tags": [
          "Arquivos"
        ],
        "summary": "Baixar arquivo por link temporário",
        "description": "Entrega documentos (faturas, propostas, relatórios) por link assinado de uso único, gerado pela própria plataforma e enviado por e-mail. Não requer token de parceiro: a autorização está no próprio link, que expira.",
        "operationId": "baixarArquivo",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Token de entrega gerado pela Tem Empresas."
          }
        ],
        "responses": {
          "200": {
            "description": "Conteúdo do arquivo.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "Link inválido, expirado ou já utilizado."
          }
        },
        "x-status": "disponivel"
      }
    },
    "/api/public/onboarding/sessao": {
      "post": {
        "tags": [
          "Jornada embarcada"
        ],
        "summary": "Abrir o primeiro acesso do beneficiário dentro do app da loja",
        "description": "Autenticação por `x-client-id` e `x-client-secret` do cliente cadastrado (não usa token de parceiro).\n\nO corpo traz `identity_token`: a credencial do **beneficiário** emitida pela TEM Saúde após o\nlogin no app. Só beneficiário entra por aqui — RH, corretora, corretor, parceiro, médico e\nbackoffice continuam autenticando na Tem Empresas.\n\nA resposta é `nada_pendente` quando não há termo nem questionário a responder, ou `pendente`\ncom um link de uso único, válido por 10 minutos, para o app abrir na WebView. Ao concluir,\navisamos a WebView com `postMessage {\"type\":\"tem:partner-finish\"}`, chamamos o `callback_url`\nassinado (`x-tem-signature`) e, se houver, seguimos para o `return_url`.",
        "operationId": "abrirSessaoOnboarding",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "identity_token"
                ],
                "properties": {
                  "identity_token": {
                    "type": "string",
                    "description": "Credencial do beneficiário (JWT)."
                  },
                  "return_url": {
                    "type": "string",
                    "description": "Endereço de volta ao app (domínio autorizado)."
                  },
                  "callback_url": {
                    "type": "string",
                    "description": "Endereço para o aviso de conclusão."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sessão aberta, ou nada pendente.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "pendente",
                        "nada_pendente"
                      ]
                    },
                    "sessaoId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "url": {
                      "type": "string"
                    },
                    "expiraEm": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "pendencias": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "termos",
                          "anamnese"
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Requisição inválida, endereço não autorizado ou sem plano ativo."
          },
          "401": {
            "description": "Credenciais do cliente ou credencial de identidade inválidas."
          }
        },
        "x-status": "disponivel"
      }
    },
    "/api/public/onboarding/sessao/{id}": {
      "get": {
        "tags": [
          "Jornada embarcada"
        ],
        "summary": "Consultar a situação da sessão de onboarding",
        "description": "Autenticação por `x-client-id` e `x-client-secret`. Devolve status, etapa e pendências da sessão — nenhum dado pessoal do beneficiário.",
        "operationId": "situacaoSessaoOnboarding",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Situação da sessão."
          },
          "401": {
            "description": "Credenciais inválidas."
          },
          "404": {
            "description": "Sessão não encontrada para este cliente."
          }
        },
        "x-status": "disponivel"
      }
    },
    "/api/public/cron/faturamento-automatico": {
      "post": {
        "tags": [
          "Rotinas internas"
        ],
        "summary": "Abrir e fechar competências de faturamento",
        "description": "Uso interno da plataforma. Autenticado pelo segredo de cron enviado em `x-cron-secret` ou `Authorization: Bearer <segredo>`; falha fechado quando o segredo não está configurado.",
        "operationId": "cron_faturamento_automatico",
        "security": [
          {
            "cronSecret": []
          }
        ],
        "responses": {
          "200": {
            "description": "Rodada executada. O corpo traz o resumo do processamento."
          },
          "401": {
            "description": "Segredo de cron ausente ou inválido."
          }
        },
        "x-status": "disponivel"
      }
    },
    "/api/public/cron/faturas-vencimento": {
      "post": {
        "tags": [
          "Rotinas internas"
        ],
        "summary": "Avisos de vencimento e inadimplência",
        "description": "Uso interno da plataforma. Autenticado pelo segredo de cron enviado em `x-cron-secret` ou `Authorization: Bearer <segredo>`; falha fechado quando o segredo não está configurado.",
        "operationId": "cron_faturas_vencimento",
        "security": [
          {
            "cronSecret": []
          }
        ],
        "responses": {
          "200": {
            "description": "Rodada executada. O corpo traz o resumo do processamento."
          },
          "401": {
            "description": "Segredo de cron ausente ou inválido."
          }
        },
        "x-status": "disponivel"
      }
    },
    "/api/public/cron/renovacoes": {
      "post": {
        "tags": [
          "Rotinas internas"
        ],
        "summary": "Renovação de contratos a vencer",
        "description": "Uso interno da plataforma. Autenticado pelo segredo de cron enviado em `x-cron-secret` ou `Authorization: Bearer <segredo>`; falha fechado quando o segredo não está configurado.",
        "operationId": "cron_renovacoes",
        "security": [
          {
            "cronSecret": []
          }
        ],
        "responses": {
          "200": {
            "description": "Rodada executada. O corpo traz o resumo do processamento."
          },
          "401": {
            "description": "Segredo de cron ausente ou inválido."
          }
        },
        "x-status": "disponivel"
      }
    },
    "/api/public/cron/vigencia-contratos": {
      "post": {
        "tags": [
          "Rotinas internas"
        ],
        "summary": "Virada de vigência e liberação de vidas",
        "description": "Uso interno da plataforma. Autenticado pelo segredo de cron enviado em `x-cron-secret` ou `Authorization: Bearer <segredo>`; falha fechado quando o segredo não está configurado.",
        "operationId": "cron_vigencia_contratos",
        "security": [
          {
            "cronSecret": []
          }
        ],
        "responses": {
          "200": {
            "description": "Rodada executada. O corpo traz o resumo do processamento."
          },
          "401": {
            "description": "Segredo de cron ausente ou inválido."
          }
        },
        "x-status": "disponivel"
      }
    },
    "/api/public/cron/tem-integra-envios": {
      "post": {
        "tags": [
          "Rotinas internas"
        ],
        "summary": "Processar a fila de envio de vidas (TEM Integra)",
        "description": "Uso interno da plataforma. Autenticado pelo segredo de cron enviado em `x-cron-secret` ou `Authorization: Bearer <segredo>`; falha fechado quando o segredo não está configurado.",
        "operationId": "cron_tem_integra_envios",
        "security": [
          {
            "cronSecret": []
          }
        ],
        "responses": {
          "200": {
            "description": "Rodada executada. O corpo traz o resumo do processamento."
          },
          "401": {
            "description": "Segredo de cron ausente ou inválido."
          }
        },
        "x-status": "disponivel"
      }
    },
    "/api/public/cron/tem-saude-envios": {
      "post": {
        "tags": [
          "Rotinas internas"
        ],
        "summary": "Processar a fila de envio de vidas (canal legado)",
        "description": "Uso interno da plataforma. Autenticado pelo segredo de cron enviado em `x-cron-secret` ou `Authorization: Bearer <segredo>`; falha fechado quando o segredo não está configurado.",
        "operationId": "cron_tem_saude_envios",
        "security": [
          {
            "cronSecret": []
          }
        ],
        "responses": {
          "200": {
            "description": "Rodada executada. O corpo traz o resumo do processamento."
          },
          "401": {
            "description": "Segredo de cron ausente ou inválido."
          }
        },
        "x-status": "disponivel"
      }
    }
  },
  "x-roadmap": [
    {
      "titulo": "Rede credenciada",
      "descricao": "Consulta de prestadores por especialidade e proximidade.",
      "status": "planejado"
    },
    {
      "titulo": "Carteirinha digital",
      "descricao": "Dados da carteirinha do beneficiário para exibição no app do parceiro.",
      "status": "planejado"
    },
    {
      "titulo": "Agendamento",
      "descricao": "Solicitação de teleconsulta e de atendimento presencial.",
      "status": "planejado"
    },
    {
      "titulo": "Webhook de eventos de vida",
      "descricao": "Notificação de inclusão, alteração e exclusão de vidas para o parceiro.",
      "status": "planejado"
    }
  ]
}