Sincronizar alunos
Objetivo: manter os alunos de uma turma do Presente iguais aos do seu sistema acadêmico. A forma recomendada é a importação CSV, que é idempotente e valida antes de gravar.
Você precisa de: uma conta com CADASTRAR na turma (por exemplo, COORDENADOR da disciplina; veja Permissões) e o identificador (id) da turma.
Visão geral
- Entrar e achar a turma (
GET /turmas). - Montar o CSV com os alunos do seu sistema.
- Simular (
modo: "simular"): nada é gravado; o relatório diz o que aconteceria. - Conferir o relatório e aplicar (
modo: "aplicar"). - Desativar quem saiu da turma no seu sistema (a importação nunca remove ninguém).
1. Achar a turma
GET /turmas lista as turmas que a conta enxerga (cada item tem id, nome, disciplinaId, instituicaoId). Para uma disciplina específica: GET /disciplinas/{disciplinaId}/turmas. Guarde o id da turma junto ao identificador dela no seu sistema.
2. O CSV
nome,email
Ana Exemplo,ana@exemplo.org
Bruno Exemplo,bruno@exemplo.org- Colunas obrigatórias:
nomeeemail. Os nomes de coluna aceitam apelidos em português, espanhol e inglês (por exemploname,nombre,correo), sem diferenciar maiúsculas nem acentos. - Separador: vírgula, ponto e vírgula ou tabulação (detectado pelo cabeçalho). Aspas duplas para valores com separador;
""para aspas dentro do valor. Aceita CRLF ou LF e BOM do Excel. - Limites: 500 linhas e 90 000 caracteres por arquivo. Acima disso, divida em vários arquivos e envie um por vez.
- O mesmo e-mail duas vezes no arquivo: a segunda ocorrência vira erro (
duplicate).
3. Simular
POST /turmas/{turmaId}/importacoes/alunos, com o CSV como texto no corpo JSON:
curl -X POST "$API/turmas/$TURMA/importacoes/alunos" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d "$(jq -n --rawfile csv alunos.csv '{csv: $csv, modo: "simular"}')"import { readFileSync } from "node:fs"
const csv = readFileSync("alunos.csv", "utf8")
const r = await fetch(`${API}/turmas/${TURMA}/importacoes/alunos`, {
method: "POST",
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
body: JSON.stringify({ csv, modo: "simular" }),
})
const relatorio = await r.json()csv = open("alunos.csv", encoding="utf-8").read()
r = requests.post(f"{API}/turmas/{TURMA}/importacoes/alunos",
headers={"Authorization": f"Bearer {token}"},
json={"csv": csv, "modo": "simular"})
relatorio = r.json()A resposta é 200 (mesmo quando há linhas com erro: erro de linha é conteúdo do relatório, não da chamada):
{
"tipo": "alunos",
"modo": "simular",
"aplicado": false,
"erroArquivo": null,
"colunaAusente": null,
"resumo": { "VALIDA": 1, "JA_EXISTE": 1 },
"linhas": [
{ "linha": 2, "situacao": "VALIDA", "rotulo": "ana@exemplo.org" },
{ "linha": 3, "situacao": "JA_EXISTE", "rotulo": "bruno@exemplo.org" }
],
"convites": null
}Situações de cada linha:
| Situação | Significado |
|---|---|
VALIDA | (só no simular) seria criada ou vinculada. |
CRIADA | Conta nova criada e matriculada; a pessoa recebe um convite por e-mail. |
VINCULADA | O e-mail já tinha conta na plataforma; a pessoa foi matriculada nesta turma. |
REATIVADA | A matrícula estava inativa e voltou. |
JA_EXISTE | Já estava matriculada: nada a fazer. Repetir a importação não duplica nem reenvia convite. |
ERRO | A linha impede a importação; campo e codigo dizem o motivo. |
codigo pode ser required, invalid, too_long, out_of_range, duplicate ou not_found. erroArquivo indica problema do arquivo todo: empty, too_many_lines, unterminated_quote, too_large ou missing_column (com colunaAusente).
O simular não revela se um e-mail já tem conta na plataforma (por privacidade); por isso convites vem null e linhas novas aparecem como VALIDA.
4. Aplicar
Repita a chamada com "modo": "aplicar". Por padrão é tudo ou nada: se alguma linha tiver ERRO, aplicado vem false e nada é gravado. Corrija o arquivo e envie de novo. Com sucesso, aplicado é true e convites diz quantos e-mails de convite saíram.
Atenção:
aplicarcom e-mails reais envia convites reais. Teste o seu código na demonstração, com dados fictícios, antes de apontar para produção.
Modo parcial
Para importar só as linhas válidas e deixar as outras para depois, use "parcial": true com uma trava de conteúdo:
simularcomparcial: true: a resposta trazhashConteudo(SHA-256 do conteúdo) econtagens(importadas,ignoradas).aplicarcomparcial: truee o mesmohashConteudo, com o mesmo arquivo. Se o arquivo mudou, a resposta é409 CONFLICT.
A resposta do aplicar parcial traz ignoradas: as linhas que ficaram de fora. Elas existem só nessa resposta (não ficam guardadas), então registre-as no seu lado.
5. Quem saiu da turma
A importação só acrescenta ou reativa. Para refletir saídas, leia as matrículas e desative quem não está mais no seu sistema:
# todas as matrículas, inclusive inativas (paginar: veja "Paginação e limites")
curl "$API/turmas/$TURMA/matriculas?limite=200&inativos=true" -H "Authorization: Bearer $TOKEN"
# desativar uma matrícula
curl -X PATCH "$API/turmas/$TURMA/matriculas/$MATRICULA" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"ativo": false}'Cada item da lista de matrículas tem id (a matrícula), usuarioId, nome, email, ativo e status da conta (CONVIDADO, ATIVO ou SUSPENSO). Compare por email com a lista do seu sistema. Desativar uma matrícula mantém o histórico de presença do aluno; para voltar, importe de novo (REATIVADA) ou envie {"ativo": true}.
Exemplo completo (JavaScript)
const auth = { Authorization: `Bearer ${token}` }
const json = { ...auth, "Content-Type": "application/json" }
async function importa(csv, modo, extra = {}) {
const r = await fetch(`${API}/turmas/${TURMA}/importacoes/alunos`, { method: "POST", headers: json, body: JSON.stringify({ csv, modo, ...extra }) })
if (!r.ok) throw new Error(`HTTP ${r.status} ${(await r.json()).code}`)
return r.json()
}
const simulacao = await importa(csv, "simular")
const erros = simulacao.linhas.filter((l) => l.situacao === "ERRO")
if (simulacao.erroArquivo || erros.length) {
console.error("Corrija o arquivo:", simulacao.erroArquivo ?? erros)
} else {
const aplicado = await importa(csv, "aplicar")
console.info(aplicado.resumo, `convites: ${aplicado.convites}`)
}Pessoas com papel (equipe)
Para criar professores, coordenadores, preceptores e auxiliares em lote, e também alunos de várias turmas de uma vez, use POST /instituicoes/{instituicaoId}/importacoes/pessoas. Exige ADMINISTRAR na instituição (CURADOR). O funcionamento é o mesmo; as colunas são:
| Coluna | Obrigatória | Valores |
|---|---|---|
nome, email | sim | Como acima. |
papel | sim | ALUNO, PROFESSOR, COORDENADOR, AUXILIAR, PRECEPTOR, CURADOR. |
disciplina | conforme o papel | A sigla da disciplina. |
turma | conforme o papel | O nome da turma (dentro da disciplina). |
avalia, cadastra | não | sim/não (aceita s, n, yes, true, 1...): marcas podeAvaliar e podeCadastrar. |
Escopo exigido por papel: ALUNO e PROFESSOR pedem disciplina e turma; COORDENADOR pede disciplina; AUXILIAR pede disciplina (e pode ter turma); CURADOR e PRECEPTOR não têm disciplina nem turma. Disciplina ou turma que não existem viram ERRO com not_found.