Cadastro de Usuários — Especificação Técnica
Plataforma Semente
1. Visão Geral
1.1 Objetivo
Este documento especifica como um sistema parceiro deve notificar a Plataforma Semente sobre a criação, atualização e desativação de usuários (alunos e professores), de forma que a base de usuários da Semente permaneça sincronizada com a base do parceiro.
A integração é feita através do envio de eventos, pelo back-end do parceiro, a um endpoint HTTP da Semente. Diferente da Integração SSO, aqui a chamada é sempre servidor-a-servidor — não há geração de token, nem qualquer participação do navegador do usuário final.
1.2 Fluxo Resumido
- Um usuário (aluno ou professor) é criado, atualizado ou desativado no sistema do parceiro.
- O sistema do parceiro monta um evento contendo os dados desse(s) usuário(s), podendo agrupar vários usuários no mesmo evento.
- O parceiro envia o evento via POST ao endpoint de Cadastro de Usuários da Semente, autenticado pelo header
apikey. - A Semente valida a apikey e o corpo da requisição.
- A Semente processa cada usuário do evento — criando, atualizando ou desativando o cadastro, conforme o campo
enabled— e responde com o resultado do processamento.
1.3 Diagrama do Fluxo
O diagrama abaixo ilustra a sequência da integração, sempre servidor-a-servidor entre o back-end do parceiro e a Plataforma Semente:
Caso a apikey seja inválida ou o corpo da requisição esteja malformado, a Semente responde com erro diretamente na chamada — o parceiro deve tratar essa resposta antes de considerar o evento como processado.
2. Pré-requisitos
2.1 Dados fornecidos pela Semente
Antes de iniciar a implementação, a Semente fornecerá ao parceiro, por canal seguro, o seguinte dado:
- apikey: chave de identificação única da instituição parceira, enviada no header
apikeyem toda requisição.
apikey — não há assinatura criptográfica do corpo da requisição.
3. Especificação do Evento
Cada requisição enviada ao endpoint representa um evento, contendo um ou mais usuários a serem sincronizados. O corpo da requisição é um JSON com a estrutura descrita a seguir.
3.1 Estrutura do Payload
{
"event_id": "evt_123456",
"timestamp": "2026-01-21T14:30:00Z",
"payload": {
"users": [
{ "...": "ver seção 3.2" }
]
}
}
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
event_id | string | Sim | Identificador único do evento, definido pelo parceiro. |
timestamp | string | Sim | Data e hora do evento, em formato ISO 8601. |
payload.users | array | Sim | Lista de usuários a serem processados neste evento (ver seção 3.2). Pode conter um ou vários usuários. |
3.2 Campos do Usuário
Cada item da lista payload.users representa um aluno ou professor:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
user_id | string | Sim | Identificador externo do usuário, definido pelo parceiro. |
nome | string | Sim | Nome completo do usuário. |
login | string | Sim | Login de acesso do usuário na Plataforma Semente. |
senha | string | Sim | Senha inicial do usuário. |
email | string | Condicional | Email do usuário. Ver regra de obrigatoriedade na seção 3.4. |
enabled | string | Sim | Status do usuário: ativar ou excluir. Ver semântica de criação/atualização/exclusão na seção 3.5. |
role | string | Sim | Perfil do usuário: aluno ou professor. |
genero | string | Sim | Gênero: masculino, feminino ou não informar. |
telefone | string | Condicional | Telefone do usuário. Obrigatório se email não for informado — ver seção 3.4. |
serie | string | Sim | Série/Ano do usuário (ex.: "6º Ano"). |
turma | string | Sim | Nome da turma do usuário (ex.: "Turma 2"). Os nomes válidos de turmas da instituição podem ser obtidos através do endpoint de Listagem de Turmas Ativas. |
send_email | string | Sim | Enviar email de boas-vindas: sim ou não. |
3.3 Professor Aplicador
Quando role for professor, dois campos adicionais indicam se ele é um professor aplicador — ou seja, se aplica atividades em turmas além da sua própria:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
applier | string | Condicional | Indica se o professor é aplicador: sim ou não. Aplicável apenas quando role for professor. |
applies | array | Condicional | Lista de séries e turmas que o professor aplica, cada item com serie e turma. Obrigatório quando applier for sim. |
{
"user_id": "prof_001",
"role": "professor",
"applier": "sim",
"applies": [
{ "serie": "6º Ano", "turma": "Turma 2" }
]
}
3.4 Regras de Obrigatoriedade
- Pelo menos um entre
emailetelefonedeve ser informado para cada usuário. Seemailnão for enviado (ou for enviado em branco),telefonepassa a ser obrigatório. appliereappliessó se aplicam quandoroleforprofessor; pararole: "aluno", esses campos não são necessários.appliessó é obrigatório quandoapplierfor"sim".
3.5 Criação, Atualização e Exclusão
O mesmo endpoint atende os três casos — criação, atualização e exclusão de usuário — sem a necessidade de rotas ou eventos distintos. O campo login funciona como chave de identificação do usuário na Plataforma Semente:
- Se o
loginenviado ainda não existe na base da Semente, o usuário é criado com os dados informados. - Se o
loginenviado já existe, o usuário é atualizado — todos os campos enviados no evento sobrescrevem os valores atualmente cadastrados para esse usuário.
A exclusão de usuário é feita de forma lógica (soft delete), através do campo enabled: ao enviar um evento para um login existente com enabled igual a excluir, a Semente marca esse usuário como desativado, sem removê-lo fisicamente da base.
4. Endpoint de Integração
4.1 URL e Método
A requisição HTTP POST com o evento deve ser enviada para:
POST https://sementemvc.azurewebsites.net/Integracao/User
4.2 Headers Obrigatórios
| Header | Valor | Descrição |
|---|---|---|
apikey | <apikey fornecida pela Semente> | Identifica a instituição parceira que está enviando o evento. |
Content-Type | application/json | Corpo da requisição enviado como JSON. |
4.3 Formato da Requisição
Exemplo de evento contendo um aluno e um professor aplicador:
POST /Integracao/User HTTP/1.1
Host: sementemvc.azurewebsites.net
apikey: SUA_APIKEY
Content-Type: application/json
{
"event_id": "evt_123456",
"timestamp": "2026-01-21T14:30:00Z",
"payload": {
"users": [
{
"user_id": "aluno_001",
"nome": "Aluno Integração",
"login": "aluno-integracao",
"senha": "123456",
"email": "aluno_integracao@escola.com",
"enabled": "ativar",
"role": "aluno",
"genero": "masculino",
"telefone": "11955555555",
"serie": "6º Ano",
"turma": "Turma 2",
"send_email": "não"
},
{
"user_id": "prof_001",
"nome": "Professor Integração",
"login": "prof-integracao",
"senha": "123456",
"email": "prof_integracao@escola.com",
"enabled": "ativar",
"role": "professor",
"genero": "masculino",
"telefone": "11955555555",
"serie": "Adultos",
"turma": "adultos",
"send_email": "não",
"applier": "sim",
"applies": [
{ "serie": "6º Ano", "turma": "Turma 2" }
]
}
]
}
}
4.4 Respostas
Em caso de sucesso, a Semente aceita e processa o evento:
HTTP/1.1 200 OK
Content-Type: application/json
{
"...": "resultado do processamento de cada usuário do evento"
}
Em caso de falha:
| HTTP | Situação | Descrição |
|---|---|---|
| 200 | Sucesso | Evento aceito e processado. Ver observação acima sobre o corpo da resposta. |
| 400 | Requisição inválida | Corpo da requisição em JSON malformado. |
| 401 | Não autorizado | Assinatura inválida. |
| 404 | Não encontrado | ApiKey inválida (não corresponde a nenhuma instituição cadastrada). |
apikey (ver seção 2.1) — não há assinatura de payload a ser gerada pelo parceiro. Esse é o texto retornado pelo endpoint quando a apikey enviada não é aceita.
5. Exemplos de Chamada
A seguir, exemplos de como montar e enviar a requisição nas linguagens mais comuns, usando apenas bibliotecas padrão (sem dependências externas).
5.1 C# (.NET)
Biblioteca: System.Net.Http (nativa, sem dependências adicionais).
using System.Net.Http;
using System.Text;
// apikey é fornecida pela Semente no provisionamento
string apikey = "SUA_APIKEY";
string url = "https://sementemvc.azurewebsites.net/Integracao/User";
string json = """
{
"event_id": "evt_123456",
"timestamp": "2026-01-21T14:30:00Z",
"payload": {
"users": [
{
"user_id": "aluno_001",
"nome": "Aluno Integração",
"login": "aluno-integracao",
"senha": "123456",
"email": "aluno_integracao@escola.com",
"enabled": "ativar",
"role": "aluno",
"genero": "masculino",
"telefone": "11955555555",
"serie": "6º Ano",
"turma": "Turma 2",
"send_email": "não"
}
]
}
}
""";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("apikey", apikey);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
5.2 Python
Biblioteca: requests (pip install requests).
import requests
# apikey é fornecida pela Semente no provisionamento
apikey = "SUA_APIKEY"
url = "https://sementemvc.azurewebsites.net/Integracao/User"
body = {
"event_id": "evt_123456",
"timestamp": "2026-01-21T14:30:00Z",
"payload": {
"users": [
{
"user_id": "aluno_001",
"nome": "Aluno Integração",
"login": "aluno-integracao",
"senha": "123456",
"email": "aluno_integracao@escola.com",
"enabled": "ativar",
"role": "aluno",
"genero": "masculino",
"telefone": "11955555555",
"serie": "6º Ano",
"turma": "Turma 2",
"send_email": "não"
}
]
}
}
response = requests.post(url, json=body, headers={"apikey": apikey})
5.3 Java
Biblioteca: java.net.http.HttpClient (nativa a partir do JDK 11).
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
// apikey é fornecida pela Semente no provisionamento
String apikey = "SUA_APIKEY";
String url = "https://sementemvc.azurewebsites.net/Integracao/User";
String json = """
{
"event_id": "evt_123456",
"timestamp": "2026-01-21T14:30:00Z",
"payload": {
"users": [
{
"user_id": "aluno_001",
"nome": "Aluno Integração",
"login": "aluno-integracao",
"senha": "123456",
"email": "aluno_integracao@escola.com",
"enabled": "ativar",
"role": "aluno",
"genero": "masculino",
"telefone": "11955555555",
"serie": "6º Ano",
"turma": "Turma 2",
"send_email": "não"
}
]
}
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("apikey", apikey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
5.4 Node.js
fetch nativo (Node.js 18+, sem dependências adicionais).
// apikey é fornecida pela Semente no provisionamento
const apikey = "SUA_APIKEY";
const url = "https://sementemvc.azurewebsites.net/Integracao/User";
const body = {
event_id: "evt_123456",
timestamp: "2026-01-21T14:30:00Z",
payload: {
users: [
{
user_id: "aluno_001",
nome: "Aluno Integração",
login: "aluno-integracao",
senha: "123456",
email: "aluno_integracao@escola.com",
enabled: "ativar",
role: "aluno",
genero: "masculino",
telefone: "11955555555",
serie: "6º Ano",
turma: "Turma 2",
send_email: "não"
}
]
}
};
const response = await fetch(url, {
method: "POST",
headers: { "apikey": apikey, "Content-Type": "application/json" },
body: JSON.stringify(body)
});
5.5 PHP
Extensão: curl (nativa em praticamente qualquer instalação PHP).
<?php
// apikey é fornecida pela Semente no provisionamento
$apikey = "SUA_APIKEY";
$url = "https://sementemvc.azurewebsites.net/Integracao/User";
$body = [
"event_id" => "evt_123456",
"timestamp" => "2026-01-21T14:30:00Z",
"payload" => [
"users" => [
[
"user_id" => "aluno_001",
"nome" => "Aluno Integração",
"login" => "aluno-integracao",
"senha" => "123456",
"email" => "aluno_integracao@escola.com",
"enabled" => "ativar",
"role" => "aluno",
"genero" => "masculino",
"telefone" => "11955555555",
"serie" => "6º Ano",
"turma" => "Turma 2",
"send_email" => "não"
]
]
]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"apikey: {$apikey}",
"Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
6. Checklist de Implementação
7. Perguntas Frequentes
payload.users é uma lista — é possível enviar um ou vários usuários no mesmo evento.enabled do usuário definido como "excluir".applier for "não", o campo applies não é necessário.