Repository navigation
Referencia da API
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.
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.
| 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
GETpode ser repetido à vontade. -
Idempotente significa que repetir a mesma requisição tem o mesmo efeito de fazer uma vez. Enviar o mesmo
PUTduas vezes deixa o segurado no mesmo estado. Isso importa quando a rede falha: um cliente pode repetir umPUTcom tranquilidade, mas deve tomar cuidado ao repetir umPOSTde cadastro.
💡 Por que as ações são
POSTem sub-recursos, e nãoPATCHno status? A API modela ações de negócio:POST /api/sinistros/{id}/aprovacao, e nãoPATCH { "status": "Aprovado" }. UmPATCHde 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.
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.
| 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.
| 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 |
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.
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
}Busca um segurado ativo.
| Resposta | Quando |
|---|---|
200 |
Mesmo formato de um item da listagem |
404 |
Não existe ou está inativo |
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.
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 |
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 |
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 |
| Resposta | Quando |
|---|---|
200 |
Mesmo formato de um item da listagem |
404 |
Apólice inexistente |
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 |
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 |
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 |
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 |
| Resposta | Quando |
|---|---|
200 |
Mesmo formato de um item da listagem |
404 |
Sinistro inexistente |
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 |
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).
-
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.
- Suba a API e abra o Swagger em
/swagger. Cada endpoint desta página aparece lá, com o botão "Try it out". - Faça um
GET /api/segurados?tamanhoPagina=101e leia a mensagem de erro. - Cadastre uma apólice e use o cabeçalho
Locationda resposta para buscá-la. - Repita uma requisição inválida com
Accept-Language: en.
- Para entender o formato de erro em profundidade: Tratamento de Erros.
- Para seguir uma requisição pelos logs: Observabilidade.
PolicyDesk · Distribuído sob a licença MIT · Repositório
Comece aqui
Como o sistema é feito
A API
Engenharia
Prática
Consulta