Logo

Agravos - Endpoints

Referência completa dos endpoints do módulo de agravos da API Sinapse

Endpoints de Agravos

O módulo de agravos gerencia casos de doenças de notificação obrigatória como dengue, zika e chikungunya.

Listar Tipos de Agravos

Retorna todos os tipos de agravos disponíveis no sistema.

GET /api/v1/agravos/tipos
Authorization: Bearer {access_token}

Permissão necessária: agravos.listar

Success Response (200):

{
  "total": 3,
  "tipos": [
    {
      "codigo": "dengue",
      "nome": "Dengue",
      "cid10_codes": ["A90", "A91"],
      "descricao": "Dengue clássica e hemorrágica",
      "notificacao_obrigatoria": true
    },
    {
      "codigo": "zika",
      "nome": "Zika",
      "cid10_codes": ["U06.9"],
      "descricao": "Infecção pelo vírus Zika",
      "notificacao_obrigatoria": true
    },
    {
      "codigo": "chikungunya",
      "nome": "Chikungunya",
      "cid10_codes": ["A92.0"],
      "descricao": "Febre de Chikungunya",
      "notificacao_obrigatoria": true
    }
  ]
}

JavaScript:

async function listarTiposAgravos() {
  const response = await fetch('/api/v1/agravos/tipos', {
    headers: {
      'Authorization': `Bearer ${accessToken}`
    }
  });
  
  if (response.ok) {
    const tipos = await response.json();
    tipos.items.forEach(tipo => {
      console.log(`${tipo.nome} (${tipo.codigo})`);
      console.log(`CID-10: ${tipo.cid10_codes.join(', ')}`);
    });
  }
}

Listar Casos

Lista casos de agravos com suporte a filtros e paginação.

GET /api/v1/agravos/casos
Authorization: Bearer {access_token}

Query Parameters:

ParâmetroTipoDescrição
pageintegerNúmero da página (padrão: 1)
sizeintegerItens por página (padrão: 50, máx: 100)
agravo_codigostringFiltrar por código do agravo (dengue, zika, chikungunya)
data_iniciodateData inicial de notificação (YYYY-MM-DD)
data_fimdateData final de notificação (YYYY-MM-DD)
estadostringUF de residência (ex: SP)
municipiostringMunicípio de residência
classificacaostringClassificação final (confirmado, descartado, etc)
sortstringCampo para ordenação [Em breve]
orderstringDireção (asc, desc) [Em breve]

Permissão necessária: agravos.listar

Success Response (200):

{
  "total": 1523,
  "page": 1,
  "size": 50,
  "pages": 31,
  "tipos": [
    {
      "id": 1234,
      "tipo_agravo": "dengue",
      "numero_notificacao": "2025-001234",
      "data_notificacao": "2025-07-29T10:30:00-03:00",
      "data_inicio_sintomas": "2025-07-25",
      "paciente": {
        "nome": "PACIENTE ANONIMIZADO",
        "idade": 35,
        "sexo": "F",
        "gestante": false
      },
      "endereco": {
        "municipio_residencia": "São Paulo",
        "estado_residencia": "SP",
        "bairro": "Centro",
        "zona": "urbana"
      },
      "classificacao_final": "dengue_com_sinais_alarme",
      "criterio_confirmacao": "laboratorial",
      "evolucao": "cura",
      "hospitalizacao": true,
      "dados_especificos": {
        "sorotipo": "DENV-2",
        "prova_laco": "positiva",
        "manifestacoes_hemorragicas": true
      },
      "unidade_notificante": {
        "nome": "Hospital Municipal",
        "cnes": "1234567"
      },
      "criado_em": "2025-07-29T10:35:00-03:00",
      "atualizado_em": "2025-07-29T14:20:00-03:00"
    }
  ],
  // "agregacoes": {...} **[Em breve]**
}

Python com Filtros:

import requests
from datetime import datetime, timedelta

def buscar_casos_dengue_sp():
    # Casos de dengue em SP nos últimos 30 dias
    data_fim = datetime.now().date()
    data_inicio = data_fim - timedelta(days=30)
    
    params = {
        'tipo_agravo': 'dengue',
        'estado': 'SP',
        'data_notificacao_inicio': data_inicio.isoformat(),
        'data_notificacao_fim': data_fim.isoformat(),
        'page': 1,
        'size': 100,
        'sort': 'data_notificacao',
        'order': 'desc'
    }
    
    headers = {'Authorization': f'Bearer {token}'}
    
    response = requests.get(
        'https://api.sinapse.org.br/v1/agravos/casos',
        params=params,
        headers=headers
    )
    
    if response.status_code == 200:
        data = response.json()
        print(f"Total de casos: {data['total']}")
        
        # Processar casos
        for caso in data['items']:
            print(f"Caso {caso['numero_notificacao']}: "
                  f"{caso['municipio_residencia']} - "
                  f"{caso['classificacao_final']}")
        
        return data

JavaScript com Paginação:

class AgravosPaginator {
  constructor(apiClient) {
    this.api = apiClient;
  }
  
  async *listarTodosCasos(filtros = {}) {
    let page = 1;
    let hasMore = true;
    
    while (hasMore) {
      const params = new URLSearchParams({
        ...filtros,
        page: page,
        size: 100
      });
      
      const response = await this.api.get(
        `/agravos/casos?${params}`
      );
      
      if (!response.ok) {
        throw new Error('Erro ao buscar casos');
      }
      
      const data = await response.json();
      
      // Yield cada caso individualmente
      for (const caso of data.items) {
        yield caso;
      }
      
      hasMore = page < data.pages;
      page++;
    }
  }
}

// Uso
const paginator = new AgravosPaginator(apiClient);

for await (const caso of paginator.listarTodosCasos({
  tipo_agravo: 'dengue',
  estado: 'RJ'
})) {
  console.log(`Processando caso ${caso.numero_notificacao}`);
  // Processar cada caso
}

Criar Caso

Registra um novo caso de agravo.

POST /api/v1/agravos/casos
Authorization: Bearer {access_token}
Content-Type: application/json

Body Parameters:

{
  "tipo_agravo": "dengue",
  "numero_notificacao": "2025-001235",
  "data_notificacao": "2025-07-29",
  "data_inicio_sintomas": "2025-07-25",
  "paciente_nome": "João da Silva",
  "paciente_data_nascimento": "1990-05-15",
  "paciente_sexo": "M",
  "paciente_gestante": false,
  "paciente_raca": "parda",
  "paciente_escolaridade": "medio_completo",
  "municipio_residencia": "São Paulo",
  "estado_residencia": "SP",
  "bairro_residencia": "Vila Mariana",
  "zona_residencia": "urbana",
  "municipio_infeccao": "São Paulo",
  "estado_infeccao": "SP",
  "pais_infeccao": "Brasil",
  "classificacao_inicial": "dengue_classico",
  "criterio_confirmacao": "clinico_epidemiologico",
  "dados_especificos": {
    "febre": true,
    "mialgia": true,
    "cefaleia": true,
    "exantema": false,
    "nausea": true,
    "dor_retro_orbital": true,
    "artralgia": true,
    "petequias": false,
    "prova_laco": "nao_realizada",
    "sinais_alarme": false
  }
}

Permissão necessária: agravos.criar

Success Response (201):

{
  "id": 1235,
  "tipo_agravo": "dengue",
  "numero_notificacao": "2025-001235",
  "status": "em_investigacao",
  "criado_em": "2025-07-29T11:00:00-03:00",
  "mensagem": "Caso criado com sucesso"
}

Error Response (422):

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Dados inválidos",
    "details": [
      {
        "field": "paciente_data_nascimento",
        "message": "Data de nascimento não pode ser futura"
      },
      {
        "field": "dados_especificos.prova_laco",
        "message": "Valor inválido. Opções: positiva, negativa, nao_realizada"
      }
    ]
  }
}

React Form Component:

function FormularioAgravo() {
  const [formData, setFormData] = useState({
    tipo_agravo: 'dengue',
    numero_notificacao: '',
    data_notificacao: new Date().toISOString().split('T')[0],
    // ... outros campos
  });
  
  const [dadosEspecificos, setDadosEspecificos] = useState({
    febre: false,
    mialgia: false,
    cefaleia: false,
    // ... outros sintomas
  });
  
  const handleSubmit = async (e) => {
    e.preventDefault();
    
    const payload = {
      ...formData,
      dados_especificos: dadosEspecificos
    };
    
    try {
      const response = await fetch('/api/v1/agravos/casos', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${accessToken}`
        },
        body: JSON.stringify(payload)
      });
      
      if (response.ok) {
        const result = await response.json();
        alert(`Caso ${result.numero_notificacao} criado com sucesso!`);
        // Redirecionar ou limpar formulário
      } else if (response.status === 422) {
        const error = await response.json();
        // Mostrar erros de validação
        error.error.details.forEach(detail => {
          console.error(`${detail.field}: ${detail.message}`);
        });
      }
    } catch (error) {
      console.error('Erro ao criar caso:', error);
    }
  };
  
  return (
    <form onSubmit={handleSubmit}>
      {/* Campos do formulário */}
    </form>
  );
}

Buscar Caso

Retorna detalhes completos de um caso específico.

GET /api/v1/agravos/casos/{id}
Authorization: Bearer {access_token}

Path Parameters:

ParâmetroTipoDescrição
idintegerID do caso

Query Parameters:

ParâmetroTipoDescrição
includestringIncluir relações: historico,anexos,investigacao [Em breve]

Permissão necessária: agravos.listar

Success Response (200):

{
  "id": 1234,
  "tipo_agravo": "dengue",
  "numero_notificacao": "2025-001234",
  "data_notificacao": "2025-07-29T10:30:00-03:00",
  "data_inicio_sintomas": "2025-07-25",
  "paciente": {
    "nome": "PACIENTE ANONIMIZADO",
    "idade": 35,
    "sexo": "F",
    "gestante": false,
    "raca": "branca",
    "escolaridade": "superior_completo",
    "ocupacao": "professora"
  },
  "endereco": {
    "logradouro": "Rua das Flores",
    "numero": "123",
    "bairro": "Centro",
    "municipio_residencia": "São Paulo",
    "estado_residencia": "SP",
    "cep": "01234-567",
    "zona": "urbana",
    "latitude": -23.550520,
    "longitude": -46.633308
  },
  "dados_clinicos": {
    "sinais_sintomas": {
      "febre": true,
      "mialgia": true,
      "cefaleia": true,
      "exantema": false,
      "nausea": true,
      "dor_retro_orbital": true,
      "artralgia": true,
      "dor_abdominal": false,
      "vomito_persistente": false,
      "hepatomegalia": false,
      "sangramento_mucosa": false,
      "letargia": false,
      "acumulo_liquidos": false
    },
    "sinais_alarme": false,
    "comorbidades": ["hipertensao", "diabetes"],
    "hospitalizacao": true,
    "data_internacao": "2025-07-26",
    "uti": false
  },
  "dados_laboratoriais": {
    "ns1": "reagente",
    "igm": "nao_reagente",
    "pcr": "detectado",
    "isolamento_viral": "DENV-2",
    "plaquetas": 95000,
    "hematocrito": 48
  },
  "classificacao_final": "dengue_com_sinais_alarme",
  "criterio_confirmacao": "laboratorial",
  "evolucao": "cura",
  "data_encerramento": "2025-08-05",
  "investigacao": {
    "locais_frequentados": [
      {
        "local": "Trabalho",
        "endereco": "Av. Paulista, 1000",
        "periodo": "diariamente"
      }
    ],
    "viagem_recente": false,
    "contato_casos_similares": true
  },
  "historico": [
    {
      "data": "2025-07-29T10:35:00-03:00",
      "acao": "caso_criado",
      "usuario": "Maria Silva",
      "detalhes": "Notificação inicial"
    },
    {
      "data": "2025-07-30T14:20:00-03:00",
      "acao": "resultado_laboratorial",
      "usuario": "Sistema",
      "detalhes": "PCR positivo para DENV-2"
    }
  ],
  "unidade_notificante": {
    "nome": "Hospital Municipal",
    "cnes": "1234567",
    "telefone": "(11) 3456-7890",
    "responsavel": "Dr. João Santos"
  }
}

Atualizar Caso

Atualiza informações de um caso existente.

PUT /api/v1/agravos/casos/{id}
Authorization: Bearer {access_token}
Content-Type: application/json

Body Parameters:

Envie apenas os campos que deseja atualizar:

{
  "classificacao_final": "dengue_grave",
  "evolucao": "obito",
  "data_obito": "2025-08-01",
  "dados_laboratoriais": {
    "igm": "reagente",
    "plaquetas": 45000
  }
}

Permissão necessária: agravos.editar

Success Response (200):

{
  "id": 1234,
  "message": "Caso atualizado com sucesso",
  // "campos_alterados": [...] **[Em breve]**
  "atualizado_em": "2025-07-30T16:45:00-03:00"
}

JavaScript - Atualização Parcial:

async function atualizarResultadoLaboratorial(casoId, resultados) {
  const response = await fetch(`/api/v1/agravos/casos/${casoId}`, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${accessToken}`
    },
    body: JSON.stringify({
      dados_laboratoriais: resultados,
      classificacao_final: determinarClassificacao(resultados)
    })
  });
  
  if (response.ok) {
    const result = await response.json();
    console.log('Campos alterados:', result.campos_alterados);
  }
}

function determinarClassificacao(lab) {
  if (lab.plaquetas < 50000 || lab.hematocrito > 50) {
    return 'dengue_grave';
  } else if (lab.plaquetas < 100000) {
    return 'dengue_com_sinais_alarme';
  }
  return 'dengue_sem_sinais_alarme';
}

Deletar Caso

Remove um caso do sistema (soft delete).

DELETE /api/v1/agravos/casos/{id}
Authorization: Bearer {access_token}

Query Parameters:

ParâmetroTipoDescrição
motivostringMotivo da exclusão [Em breve]
forcebooleanExclusão permanente (requer permissão especial) [Em breve]

Permissão necessária: agravos.deletar

Success Response (204):

Sem conteúdo de resposta

Error Response (400):

{
  "error": {
    "code": "MISSING_REASON",
    "message": "Motivo da exclusão é obrigatório"
  }
}

Importação em Massa [Em breve]

Importa múltiplos casos através de arquivo.

POST /api/v1/agravos/casos/bulk
Authorization: Bearer {access_token}
Content-Type: multipart/form-data

Form Data:

CampoTipoObrigatórioDescrição
filefileSimArquivo CSV ou Excel
formatostringSimFormato: csv, xlsx
modostringNãoModo: validar, importar (padrão: validar)
ignorar_errosbooleanNãoContinuar em caso de erros

Permissão necessária: agravos.importar

Success Response (202):

{
  "job_id": "import_20250729_110000",
  "status": "processing",
  "status_url": "/api/v1/jobs/import_20250729_110000",
  "message": "Importação iniciada"
}

Verificar Status:

{
  "job_id": "import_20250729_110000",
  "status": "completed",
  "progress": 100,
  "resultado": {
    "total_linhas": 500,
    "importados": 485,
    "erros": 15,
    "avisos": 23,
    "tempo_processamento": "45.3s",
    "erros_detalhados": [
      {
        "linha": 23,
        "numero_notificacao": "2025-001256",
        "erro": "Data de nascimento inválida"
      }
    ]
  }
}

HTML Form com Progress:

<form id="importForm">
  <input type="file" id="fileInput" accept=".csv,.xlsx" />
  <button type="submit">Importar</button>
  <div id="progress" style="display: none;">
    <progress id="progressBar" max="100" value="0"></progress>
    <span id="progressText">0%</span>
  </div>
</form>

<script>
document.getElementById('importForm').addEventListener('submit', async (e) => {
  e.preventDefault();
  
  const fileInput = document.getElementById('fileInput');
  const file = fileInput.files[0];
  
  if (!file) {
    alert('Selecione um arquivo');
    return;
  }
  
  const formData = new FormData();
  formData.append('file', file);
  formData.append('formato', file.name.endsWith('.xlsx') ? 'xlsx' : 'csv');
  formData.append('modo', 'importar');
  
  // Iniciar importação
  const response = await fetch('/api/v1/agravos/casos/bulk', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`
    },
    body: formData
  });
  
  if (response.ok) {
    const { job_id, status_url } = await response.json();
    
    // Mostrar progresso
    document.getElementById('progress').style.display = 'block';
    
    // Verificar status periodicamente
    const interval = setInterval(async () => {
      const statusResponse = await fetch(status_url, {
        headers: {
          'Authorization': `Bearer ${accessToken}`
        }
      });
      
      const status = await statusResponse.json();
      
      // Atualizar progresso
      document.getElementById('progressBar').value = status.progress;
      document.getElementById('progressText').textContent = `${status.progress}%`;
      
      if (status.status === 'completed' || status.status === 'failed') {
        clearInterval(interval);
        
        if (status.status === 'completed') {
          alert(`Importação concluída!
            Total: ${status.resultado.total_linhas}
            Importados: ${status.resultado.importados}
            Erros: ${status.resultado.erros}`);
        } else {
          alert('Erro na importação');
        }
      }
    }, 2000); // Verificar a cada 2 segundos
  }
});
</script>

Estatísticas

Retorna estatísticas resumidas dos casos.

GET /api/v1/agravos/casos/estatisticas/resumo
Authorization: Bearer {access_token}

Query Parameters:

ParâmetroTipoDescrição
data_iniciodateData inicial
data_fimdateData final
tipo_agravostringFiltrar por tipo
estadostringFiltrar por UF
agregacaostringTipo: dia, semana, mes [Em breve]
metricasstringMétricas: casos,obitos,incidencia [Em breve]

Permissão necessária: agravos.estatisticas

Success Response (200):

{
  "periodo": {
    "inicio": "2025-07-01",
    "fim": "2025-07-29"
  },
  "total": 3456,
  "por_classificacao": {
    "confirmado": 2890,
    "descartado": 566
  },
  "hospitalizados": 456,
  "obitos": 23,
  "taxa_hospitalizacao": 13.2,
  "taxa_obito": 0.7,
  // "por_tipo": {...} **[Em breve]**
  // "serie_temporal": [...] **[Em breve]** 
  // "distribuicao_geografica": {...} **[Em breve]**
  // "faixa_etaria": {...} **[Em breve]**
}

Dashboard com Chart.js:

async function carregarEstatisticas() {
  const params = new URLSearchParams({
    data_inicio: '2025-07-01',
    data_fim: '2025-07-29',
    agregacao: 'dia',
    metricas: 'casos,obitos,incidencia'
  });
  
  const response = await fetch(
    `/api/v1/agravos/casos/estatisticas?${params}`,
    {
      headers: {
        'Authorization': `Bearer ${accessToken}`
      }
    }
  );
  
  const stats = await response.json();
  
  // Gráfico de série temporal
  const ctx = document.getElementById('graficoTemporal').getContext('2d');
  new Chart(ctx, {
    type: 'line',
    data: {
      labels: stats.serie_temporal.map(d => d.data),
      datasets: [{
        label: 'Casos Novos',
        data: stats.serie_temporal.map(d => d.casos_novos),
        borderColor: 'rgb(75, 192, 192)',
        tension: 0.1
      }, {
        label: 'Óbitos',
        data: stats.serie_temporal.map(d => d.obitos_novos),
        borderColor: 'rgb(255, 99, 132)',
        tension: 0.1
      }]
    },
    options: {
      responsive: true,
      plugins: {
        title: {
          display: true,
          text: 'Evolução Temporal dos Casos'
        }
      }
    }
  });
  
  // Gráfico de pizza por tipo
  const ctx2 = document.getElementById('graficoPorTipo').getContext('2d');
  new Chart(ctx2, {
    type: 'doughnut',
    data: {
      labels: Object.keys(stats.por_tipo),
      datasets: [{
        data: Object.values(stats.por_tipo).map(t => t.casos),
        backgroundColor: [
          'rgb(255, 99, 132)',
          'rgb(54, 162, 235)',
          'rgb(255, 205, 86)'
        ]
      }]
    }
  });
  
  // Tabela de distribuição geográfica
  const tbody = document.getElementById('tabelaGeografica');
  tbody.innerHTML = '';
  
  Object.entries(stats.distribuicao_geografica).forEach(([uf, dados]) => {
    const row = tbody.insertRow();
    row.insertCell(0).textContent = uf;
    row.insertCell(1).textContent = dados.casos.toLocaleString();
    row.insertCell(2).textContent = `${dados.incidencia.toFixed(1)}/100mil`;
    row.insertCell(3).textContent = dados.municipios_afetados;
  });
}

Mapa de Calor [Em breve]

Retorna dados para visualização geográfica.

GET /api/v1/agravos/casos/mapa-calor
Authorization: Bearer {access_token}

Query Parameters:

ParâmetroTipoDescrição
nivelstringNível: municipio, bairro, cep
tipo_agravostringFiltrar por tipo
periodointegerÚltimos N dias
boundsstringLimites do mapa (lat,lng,lat,lng)

Success Response (200):

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [-46.633308, -23.550520]
      },
      "properties": {
        "municipio": "São Paulo",
        "bairro": "Centro",
        "casos": 45,
        "intensidade": 0.8,
        "radius": 500
      }
    }
  ],
  "metadata": {
    "total_pontos": 234,
    "max_casos": 89,
    "min_casos": 1,
    "periodo": "ultimos_30_dias"
  }
}

Anexos [Em breve]

Upload de Anexo [Em breve]

POST /api/v1/agravos/casos/{id}/anexos
Authorization: Bearer {access_token}
Content-Type: multipart/form-data

Form Data:

CampoTipoDescrição
arquivofileArquivo (PDF, imagem)
tipostringTipo: exame, notificacao, outro
descricaostringDescrição do anexo

Success Response (201):

{
  "id": 789,
  "nome": "hemograma_20250729.pdf",
  "tipo": "exame",
  "tamanho": 245678,
  "url": "/api/v1/agravos/anexos/789/download",
  "uploaded_at": "2025-07-29T11:30:00-03:00"
}

Próximos Passos

On this page