Skip to content

Referencia da API

rodrigosdk edited this page Nov 12, 2026 · 4 revisions

Referência da API: como conversar com o PolicyDesk

Para quem é este artigo: para quem vai consumir a API (um front-end, um aplicativo, outro sistema) e para quem está aprendendo como APIs REST funcionam.

Pré-requisitos: nenhum. A primeira parte explica os conceitos; a segunda é a referência completa, endpoint por endpoint.

O que você vai aprender: como uma requisição HTTP é montada, o que cada código de status significa, as convenções desta API e todos os endpoints, com exemplos.


Parte 1: o básico de uma API REST

Anatomia de uma requisição

Toda conversa com a API é um par requisição e resposta. Uma requisição tem quatro partes:

POST /api/apolices/1f0e2d3c-4b5a-6978-8796-a5b4c3d2e1f0/sinistros HTTP/1.1   ← método + caminho
Host: localhost:8080                                                         ← cabeçalhos
Content-Type: application/json
Accept-Language: pt-BR

{ "descricao": "Colisão traseira", "valor": 8000, "dataOcorrencia": "2026-10-15" }   ← corpo
Parte O que é Exemplo
Método O verbo: o que você quer fazer GET lê, POST cria ou executa uma ação, PUT substitui, DELETE remove
Caminho O recurso: sobre o que você quer agir /api/apolices/{id}/sinistros: os sinistros de uma apólice
Cabeçalhos Metadados da requisição Content-Type diz o formato do corpo; Accept-Language pede um idioma
Corpo Os dados enviados, em JSON Os campos do sinistro

A resposta tem um código de status (um número de três dígitos), cabeçalhos e, às vezes, um corpo.

O que os métodos significam aqui

Método Uso no PolicyDesk É seguro? É idempotente?
GET Consultar Sim Sim
POST Cadastrar, e executar ações de negócio (/aprovacao, /cancelamento) Não Não
PUT Atualizar os dados de um segurado Não Sim
DELETE Inativar um segurado Não Sim
  • Seguro significa que não altera nada. Um GET pode ser repetido à vontade.
  • Idempotente significa que repetir a mesma requisição tem o mesmo efeito de fazer uma vez. Enviar o mesmo PUT duas vezes deixa o segurado no mesmo estado. Isso importa quando a rede falha: um cliente pode repetir um PUT com tranquilidade, mas deve tomar cuidado ao repetir um POST de cadastro.

💡 Por que as ações são POST em sub-recursos, e não PATCH no status? A API modela ações de negócio: POST /api/sinistros/{id}/aprovacao, e não PATCH { "status": "Aprovado" }. Um PATCH de status deixaria o cliente "pular" para qualquer estado, e misturaria transições com regras diferentes em um só endpoint. Com uma ação por endpoint, cada uma tem suas regras, suas mensagens e sua documentação.

Os códigos de status, explicados

O primeiro dígito diz a categoria: 2xx deu certo, 4xx o problema está na requisição (o cliente pode corrigir), 5xx o problema está no servidor.

Código Nome Quando o PolicyDesk responde O que o cliente deve fazer
200 OK Uma consulta deu certo Ler o corpo
201 Created Algo foi criado. O corpo traz { "id": ... } e o cabeçalho Location traz o endereço do novo recurso Guardar o id
204 No Content Uma ação deu certo e não há nada para devolver Seguir em frente
400 Bad Request Dados inválidos, uma regra de negócio violada ou JSON malformado Mostrar as mensagens de errors ao usuário
404 Not Found O recurso não existe, ou a URL é inválida Verificar o id
409 Conflict Outra operação alterou o mesmo dado ao mesmo tempo Consultar de novo e decidir se repete
499 (fora do padrão) O cliente fechou a conexão antes da resposta Nada; só aparece nos logs
500 Internal Server Error Um erro inesperado Reportar o traceId
503 Service Unavailable Só em /health, quando o banco está fora Esperar ou alertar

Todo erro tem o mesmo formato de corpo (um ProblemDetails), com uma lista de mensagens prontas para exibir:

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "instance": "/api/apolices",
  "errors": ["A descrição é obrigatória.", "O valor da cobertura deve ser maior que zero."],
  "traceId": "4bf92f3577b34da6a3ce929d0e0e4736"
}

O formato completo e suas garantias estão em Tratamento de Erros.


Parte 2: as convenções desta API

Endereços

Ambiente Base
Docker local http://localhost:8080
dotnet run http://localhost:5045
Produção https://policydesk-api-rodrigo.azurewebsites.net

A documentação interativa (/swagger) e a especificação OpenAPI (/openapi/v1.json) ficam ligadas em Development e em qualquer ambiente com Swagger:Enabled=true (variável Swagger__Enabled). Em produção a flag vem ligada pelo Bicep, para que a API possa ser testada direto pelo navegador: a raiz / redireciona para o /swagger. Para desligar, basta remover a variável.

Regras que valem para todos os endpoints

Aspecto Como funciona Por quê
Formato JSON, com propriedades em camelCase e em português (valorCobertura) O consumidor é brasileiro
Identificadores GUIDs. Um id em formato inválido não casa com a rota e resulta em 404 Ids imprevisíveis; ninguém adivinha o próximo
Datas de calendário Somente "2026-05-10". Uma data com horário ("2026-05-10T00:00:00") recebe 400 Uma data não tem horário nem fuso; aceitar horário abriria espaço para mudar de dia na conversão
Instantes ISO 8601 em UTC ("2026-11-03T14:22:10.512Z") Um ponto exato no tempo; o cliente converte para o fuso de quem lê
"Hoje" Calculado no fuso de Brasília, não em UTC Veja Entendendo o negócio
Textos Espaços nas pontas são removidos, e espaços repetidos viram um só " Maria Silva " vira "Maria Silva"
Dinheiro Número decimal, sem formatação (50000.00), com até 16 dígitos inteiros e 2 casas Mais casas seriam arredondadas em silêncio pelo banco
Status Texto em português (Ativa, EmAnalise...) Legível sem tabela de códigos
Tamanho do corpo No máximo 64 KB Proteção contra abuso
URLs Minúsculas Consistência
X-Trace-Id Presente em todas as respostas Para encontrar a requisição nos logs
Accept-Language pt-BR (padrão) ou en. Ausente ou não suportado: português Mensagens de erro no idioma do usuário

Paginação

As listagens de segurados e de apólices são paginadas: em vez de devolver todos os registros, devolvem uma "página" por vez.

Parâmetro Tipo Padrão Regras
pagina inteiro 1 A partir de 1
tamanhoPagina inteiro 20 De 1 a 100

Fora desses limites, a resposta é 400. A ordem é sempre a mesma (data de cadastro, depois id), então percorrer as páginas nunca repete nem pula registros, desde que nada seja cadastrado no meio.

A resposta vem em um "envelope":

{
  "itens": [ ... ],
  "pagina": 1,
  "tamanhoPagina": 20,
  "totalItens": 42,
  "totalPaginas": 3
}

Para percorrer tudo, peça pagina=1, pagina=2... até pagina == totalPaginas.


Parte 3: os endpoints

Segurados

GET /api/segurados

Lista os segurados ativos, paginados.

GET /api/segurados?pagina=1&tamanhoPagina=20

Resposta 200

{
  "itens": [
    {
      "id": "9b2f3c1e-0d4a-4b8e-9f6a-2c1d3e4f5a6b",
      "nome": "Maria Silva",
      "cpf": "52998224725",
      "dataNascimento": "1990-05-10",
      "email": "maria@exemplo.com",
      "telefone": "+5511987654321",
      "criadoEm": "2026-11-03T14:22:10.512Z",
      "atualizadoEm": null
    }
  ],
  "pagina": 1,
  "tamanhoPagina": 20,
  "totalItens": 1,
  "totalPaginas": 1
}

GET /api/segurados/{id}

Busca um segurado ativo.

Resposta Quando
200 Mesmo formato de um item da listagem
404 Não existe ou está inativo

POST /api/segurados

Cadastra um segurado, ou reativa um inativo com o mesmo CPF.

Campo Tipo Obrigatório Regras
nome texto ✔️ Até 150 caracteres
cpf texto ✔️ CPF válido, com ou sem máscara
dataNascimento data ✔️ Não pode ser futura
email texto ✔️ E-mail válido, até 254 caracteres; único entre os ativos
telefone texto ✔️ Válido no país de destino; sem +, é tratado como brasileiro; até 20 caracteres, sem ramal
{
  "nome": "Maria Silva",
  "cpf": "529.982.247-25",
  "dataNascimento": "1990-05-10",
  "email": "Maria@Exemplo.com",
  "telefone": "(11) 98765-4321"
}

Resposta 201, com o cabeçalho Location: /api/segurados/{id}:

{ "id": "9b2f3c1e-0d4a-4b8e-9f6a-2c1d3e4f5a6b" }
Resposta Quando
201 Cadastrado ou reativado. Na reativação, devolve o id original
400 Validação; CPF ou e-mail já usado por um segurado ativo

Os dados são normalizados antes de gravar: o CPF fica só com dígitos, o e-mail em minúsculas e o telefone no formato internacional E.164 ((11) 98765-4321 → +5511987654321). Quem exibe o telefone precisa formatá-lo.

PUT /api/segurados/{id}

Atualiza os dados de um segurado ativo. O CPF não pode ser alterado, por isso não faz parte do corpo.

Campo Tipo Obrigatório
nome texto ✔️
dataNascimento data ✔️
email texto ✔️
telefone texto ✔️

As regras são as mesmas do cadastro. Como é um PUT, todos os campos são enviados, mesmo os que não mudaram.

Resposta Quando
204 Atualizado
400 Validação, ou e-mail já usado por outro segurado ativo
404 Segurado inexistente ou inativo
409 O segurado foi alterado por outra operação ao mesmo tempo

DELETE /api/segurados/{id}

Inativa o segurado. É uma exclusão lógica: o registro permanece no banco, com o histórico.

Resposta Quando
204 Inativado
400 Tem apólice ativa em vigor hoje ou com vigência futura
404 Segurado inexistente ou já inativo
409 Uma apólice foi emitida para ele durante a operação

Apólices

GET /api/apolices

Lista as apólices, paginadas, com filtros opcionais.

Parâmetro Tipo O que filtra
seguradoId GUID Só as apólices deste segurado
status Ativa ou Cancelada Só as apólices neste status
pagina, tamanhoPagina inteiro Veja Paginação
GET /api/apolices?seguradoId=9b2f3c1e-0d4a-4b8e-9f6a-2c1d3e4f5a6b&status=Ativa&pagina=1

Resposta 200

{
  "itens": [
    {
      "id": "1f0e2d3c-4b5a-6978-8796-a5b4c3d2e1f0",
      "seguradoId": "9b2f3c1e-0d4a-4b8e-9f6a-2c1d3e4f5a6b",
      "descricao": "Seguro auto",
      "valorCobertura": 50000.00,
      "valorPremio": 2400.00,
      "inicioVigencia": "2026-01-01",
      "fimVigencia": "2026-12-31",
      "status": "Ativa",
      "criadoEm": "2026-11-03T14:25:00.000Z",
      "atualizadoEm": null
    }
  ],
  "pagina": 1,
  "tamanhoPagina": 20,
  "totalItens": 1,
  "totalPaginas": 1
}
Resposta Quando
200 Página, possivelmente vazia
400 status inexistente; pagina ou tamanhoPagina fora dos limites

GET /api/apolices/{id}

Resposta Quando
200 Mesmo formato de um item da listagem
404 Apólice inexistente

POST /api/apolices

Emite uma apólice.

Campo Tipo Obrigatório Regras
seguradoId GUID ✔️ Segurado existente e ativo
descricao texto ✔️ Até 500 caracteres
valorCobertura decimal ✔️ Maior que zero; até 2 casas decimais
valorPremio decimal ✔️ Maior que zero; até 2 casas decimais
inicioVigencia data ✔️ —
fimVigencia data ✔️ Depois de inicioVigencia
{
  "seguradoId": "9b2f3c1e-0d4a-4b8e-9f6a-2c1d3e4f5a6b",
  "descricao": "Seguro auto",
  "valorCobertura": 50000,
  "valorPremio": 2400,
  "inicioVigencia": "2026-01-01",
  "fimVigencia": "2026-12-31"
}

Resposta 201, com o cabeçalho Location: /api/apolices/{id}:

{ "id": "1f0e2d3c-4b5a-6978-8796-a5b4c3d2e1f0" }
Resposta Quando
201 Emitida
400 Validação (inclusive mais de 2 casas decimais) ou segurado inativo
404 Segurado inexistente
409 O segurado foi inativado durante a operação

POST /api/apolices/{id}/cancelamento

Cancela a apólice. Não tem corpo.

Resposta Quando
204 Cancelada
400 Já estava cancelada
404 Apólice inexistente
409 Alterada por outra operação ao mesmo tempo

Sinistros

POST /api/apolices/{id}/sinistros

Abre um sinistro na apólice {id}. Repare que a rota deixa clara a relação: o sinistro pertence à apólice.

Campo Tipo Obrigatório Regras
descricao texto ✔️ Até 500 caracteres
valor decimal ✔️ Maior que zero; até 2 casas decimais; cabe no saldo disponível da cobertura
dataOcorrencia data ✔️ Não futura (no fuso de negócio) e dentro da vigência

O saldo disponível é a cobertura menos a soma dos sinistros da apólice que não foram negados. Negar um sinistro libera o valor dele. Veja o exemplo passo a passo.

{
  "descricao": "Colisão traseira no estacionamento",
  "valor": 8000,
  "dataOcorrencia": "2026-10-15"
}

Resposta 201, com o cabeçalho Location: /api/sinistros/{id}:

{ "id": "7c6b5a49-3827-4615-9504-f3e2d1c0b9a8" }
Resposta Quando
201 Registrado com status Pendente
400 Validação; apólice cancelada; data fora da vigência; valor acima do saldo
404 Apólice inexistente
409 Outro sinistro da mesma apólice foi gravado ao mesmo tempo

GET /api/apolices/{id}/sinistros

Lista os sinistros da apólice, do mais antigo para o mais recente. Não é paginada: uma apólice tem poucos sinistros.

Resposta 200

[
  {
    "id": "7c6b5a49-3827-4615-9504-f3e2d1c0b9a8",
    "apoliceId": "1f0e2d3c-4b5a-6978-8796-a5b4c3d2e1f0",
    "descricao": "Colisão traseira no estacionamento",
    "valor": 8000.00,
    "dataOcorrencia": "2026-10-15",
    "status": "Aprovado",
    "motivoNegacao": null,
    "dataAprovacao": "2026-11-03T15:01:44.120Z",
    "dataPagamento": null,
    "criadoEm": "2026-11-03T14:30:00.000Z",
    "atualizadoEm": "2026-11-03T15:01:44.120Z"
  }
]
Resposta Quando
200 Lista, possivelmente vazia
404 Apólice inexistente

GET /api/sinistros/{id}

Resposta Quando
200 Mesmo formato de um item da listagem
404 Sinistro inexistente

As ações do fluxo do sinistro

São todas POST, sem corpo (exceto a negação), e respondem 204 quando dão certo. Cada uma corresponde a uma seta do diagrama de estados.

Endpoint Só funciona a partir de Leva para Corpo
POST /api/sinistros/{id}/analise Pendente EmAnalise —
POST /api/sinistros/{id}/aprovacao EmAnalise Aprovado —
POST /api/sinistros/{id}/negacao EmAnalise Negado { "motivo": "..." }
POST /api/sinistros/{id}/pagamento Aprovado Pago —

O corpo da negação tem um campo obrigatório, motivo, com até 1000 caracteres:

{ "motivo": "Evento não coberto pela apólice." }
Resposta Quando
204 A transição foi feita
400 O sinistro não está no status de origem exigido; motivo ausente (negação)
404 Sinistro inexistente
409 Outra transição foi gravada ao mesmo tempo

Health check

GET /health

Responde se a API está no ar e consegue falar com o banco.

Resposta Corpo Quando
200 Healthy Tudo funcionando
503 Unhealthy O banco não responde

É o endpoint que orquestradores e balanceadores de carga usam para saber se mandam tráfego para a instância, e o que o pipeline de deploy chama logo depois de publicar (veja CI/CD e Deploy).


Pontos de atenção para quem consome

  • A API não é versionada. As mudanças de contrato já feitas (nomes em português, paginação, datas sem horário) quebraram consumidores antigos sem um /v2. Se a API ganhar consumidores externos, versionar passa a ser essencial.
  • O telefone volta em E.164, não na formatação digitada.
  • "Hoje" é o dia em Brasília. Um front-end que calcule a data de hoje em UTC (por exemplo, new Date().toISOString()) vai enviar "amanhã" entre 21h e meia-noite, e receber "data futura".
  • Os sinistros de uma apólice não são paginados.

Experimente

  1. Suba a API e abra o Swagger em /swagger. Cada endpoint desta página aparece lá, com o botão "Try it out".
  2. Faça um GET /api/segurados?tamanhoPagina=101 e leia a mensagem de erro.
  3. Cadastre uma apólice e use o cabeçalho Location da resposta para buscá-la.
  4. Repita uma requisição inválida com Accept-Language: en.

Próximos passos

Clone this wiki locally