📚 API Reference¶
Referência completa da API SADIONLINE
Este documento fornece especificações técnicas detalhadas para todos os endpoints da API SADIONLINE.
📋 Índice¶
- Autenticação
- API de Estudantes
- API de Atividades
- API de Sessões
- Listar Sessões
- Obter Detalhes da Sessão
- Finalizar Sessão
- API de Análise de Engajamento
- Códigos de Erro
- Limites de Taxa
🔐 Autenticação¶
Todas as requisições da API requerem autenticação usando uma chave API no cabeçalho Authorization:
Formato da Chave API¶
- Prefixo:
sk_ - Formato:
sk_[string-aleatória-de-32-caracteres] - Exemplo:
sk_abc123def456ghi789jkl012mno345pqr678
Sistema Multi-Tenant¶
O SADIONLINE utiliza um sistema multi-tenant baseado em organizações. Cada organização possui seu próprio esquema de banco de dados isolado e conjunto de dados.
URLs com Tenant¶
Para acessar recursos específicos de uma organização, use o padrão de URL:
Exemplo:
GET /tenant/550e8400-e29b-41d4-a716-446655440002/v1/students/
Authorization: APIKey sk_sua_chave_api_aqui
URLs Públicas vs Tenant¶
| Tipo de URL | Padrão | Uso | Exemplo |
|---|---|---|---|
| Pública | /v1/{endpoint} | Gerenciamento de organizações, autenticação | /v1/organizations/ |
| Tenant | /tenant/{organization_id}/v1/{endpoint} | Recursos específicos da organização | /tenant/{org_id}/v1/students/ |
Recursos por Tipo de URL¶
URLs Públicas (/v1/): - Gerenciamento de organizações (/v1/organizations/) - Autenticação e usuários (/v1/auth/, /v1/users/) - Localização (/v1/countries/, /v1/states/) - Documentação da API (/v1/schema/)
URLs Tenant (/tenant/{organization_id}/v1/): - Estudantes (/tenant/{org_id}/v1/students/) - Atividades (/tenant/{org_id}/v1/activities/) - Sessões (/tenant/{org_id}/v1/sessions/) - Análise de engajamento (/tenant/{org_id}/v1/sessions/{id}/engagement/) - Análise de emoção (/tenant/{org_id}/v1/sessions/{id}/emotion/) - Análise cognitiva (/tenant/{org_id}/v1/sessions/{id}/cognitive/) - Insights (/tenant/{org_id}/v1/insights/)
Erros de Autenticação¶
| Código | Erro | Descrição |
|---|---|---|
401 | Chave API inválida | Chave API é inválida ou mal formada |
401 | Chave API expirada | Chave API passou da data de expiração |
403 | Acesso negado | Chave API não tem as permissões necessárias |
404 | Organização não encontrada | Organization ID inválido ou inexistente |
👥 API de Estudantes¶
Endpoint base: /tenant/{organization_id}/v1/students/
⚠️ Importante: Todos os endpoints de estudantes requerem o
organization_idna URL para acessar o tenant correto.
Criar Estudante¶
Cria um novo registro de estudante no sistema.
Endpoint: POST /tenant/{organization_id}/v1/students/
Cabeçalhos:
Corpo da Requisição:
{
"registration_code": "EST001",
"email": "estudante@exemplo.com",
"status": "ACTIVE",
"entry_date": "2024-01-15"
}
Especificações dos Campos:
| Campo | Tipo | Obrigatório | Descrição | Validação |
|---|---|---|---|---|
registration_code | string | Sim | Identificador único do estudante | Máx 50 caracteres, alfanumérico |
email | string | Sim | Endereço de email do estudante | Formato de email válido |
status | string | Sim | Status do estudante | Um de: ACTIVE, INACTIVE, FINISHED, TRANSFERRED, SUSPENDED |
entry_date | date | Sim | Data de matrícula do estudante | Formato ISO 8601 (YYYY-MM-DD) |
Resposta de Sucesso (201):
{
"success": true,
"message": "Estudante criado com sucesso",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_detail": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "estudante@exemplo.com",
"name": "EST001",
"avatar": null
},
"registration_code": "EST001",
"email": "estudante@exemplo.com",
"status": "ACTIVE",
"entry_date": "2024-01-15",
"entry_year": "2024",
"entry_semester": "1",
"class_batch": "2024.1",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"timestamp": "2024-01-15T10:30:00Z"
}
Resposta de Erro (400):
{
"success": false,
"message": "Erro de validação ocorreu",
"errors": {
"registration_code": ["Este campo é obrigatório."],
"email": ["Insira um endereço de email válido."]
},
"timestamp": "2024-01-15T10:30:00Z"
}
Listar Estudantes¶
Recupera uma lista paginada de estudantes com filtragem opcional.
Endpoint: GET /tenant/{organization_id}/v1/students/
Parâmetros de Query:
| Parâmetro | Tipo | Obrigatório | Descrição | Exemplo |
|---|---|---|---|---|
status | string | Não | Filtrar por status do estudante | ACTIVE, INACTIVE, FINISHED, TRANSFERRED, SUSPENDED |
registration_code | string | Não | Filtrar por código de matrícula (exato) | EST001 |
email | string | Não | Filtrar por email (contém) | estudante@exemplo.com |
entry_year | integer | Não | Filtrar por ano de entrada | 2024 |
entry_semester | integer | Não | Filtrar por semestre de entrada | 1, 2 |
entry_after | date | Não | Filtrar por data de entrada após | 2024-01-01 |
entry_before | date | Não | Filtrar por data de entrada antes | 2024-12-31 |
created_after | datetime | Não | Filtrar por criado após | 2024-01-15T10:30:00Z |
created_before | datetime | Não | Filtrar por criado antes | 2024-01-15T10:30:00Z |
updated_after | datetime | Não | Filtrar por atualizado após | 2024-01-15T10:30:00Z |
updated_before | datetime | Não | Filtrar por atualizado antes | 2024-01-15T10:30:00Z |
search | string | Não | Buscar em código de matrícula e email | joão |
ordering | string | Não | Ordenar resultados | created_at, -created_at, registration_code, email, status, entry_date |
page | integer | Não | Número da página para paginação | 1 |
page_size | integer | Não | Número de itens por página | 20 |
Exemplo de Requisição:
GET /tenant/550e8400-e29b-41d4-a716-446655440002/v1/students/?status=ACTIVE&ordering=-created_at&page=1&page_size=10
Authorization: APIKey sk_sua_chave_api_aqui
Accept-Language: pt-br
Resposta de Sucesso (200):
{
"success": true,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_detail": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "estudante@exemplo.com",
"name": "EST001",
"avatar": null
},
"registration_code": "EST001",
"email": "estudante@exemplo.com",
"status": "ACTIVE",
"entry_date": "2024-01-15",
"entry_year": "2024",
"entry_semester": "1",
"class_batch": "2024.1",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
],
"count": 1,
"next": null,
"previous": null,
"timestamp": "2024-01-15T10:30:00Z"
}
Obter Detalhes do Estudante¶
Recupera informações detalhadas sobre um estudante específico.
Endpoint: GET /tenant/{organization_id}/v1/students/{id}/
Parâmetros de Caminho:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | UUID | Sim | Identificador único do estudante |
Resposta de Sucesso (200):
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_detail": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "estudante@exemplo.com",
"name": "EST001",
"avatar": null
},
"registration_code": "EST001",
"email": "estudante@exemplo.com",
"status": "ACTIVE",
"entry_date": "2024-01-15",
"entry_year": "2024",
"entry_semester": "1",
"class_batch": "2024.1",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"timestamp": "2024-01-15T10:30:00Z"
}
Atualizar Estudante¶
Atualiza informações do estudante. Suporta atualizações completas (PUT) e parciais (PATCH).
Endpoint: PUT /tenant/{organization_id}/v1/students/{id}/ ou PATCH /tenant/{organization_id}/v1/students/{id}/
Corpo da Requisição (PUT - Atualização Completa):
{
"registration_code": "EST001",
"email": "atualizado@exemplo.com",
"status": "ACTIVE",
"entry_date": "2024-01-15"
}
Corpo da Requisição (PATCH - Atualização Parcial):
Resposta de Sucesso (200):
{
"success": true,
"message": "Estudante atualizado com sucesso",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_detail": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "atualizado@exemplo.com",
"name": "EST001",
"avatar": null
},
"registration_code": "EST001",
"email": "atualizado@exemplo.com",
"status": "INACTIVE",
"entry_date": "2024-01-15",
"entry_year": "2024",
"entry_semester": "1",
"class_batch": "2024.1",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T11:00:00Z"
},
"timestamp": "2024-01-15T11:00:00Z"
}
Excluir Estudante¶
Exclui um registro de estudante (exclusão suave).
Endpoint: DELETE /tenant/{organization_id}/v1/students/{id}/
Resposta de Sucesso (204):
{
"success": true,
"message": "Estudante excluído com sucesso",
"timestamp": "2024-01-15T11:00:00Z"
}
Atualizar Status do Estudante¶
Atualiza o status de um estudante específico.
Endpoint: PATCH /tenant/{organization_id}/v1/students/{id}/status/
Corpo da Requisição:
Resposta de Sucesso (200):
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"user_detail": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "estudante@exemplo.com",
"name": "EST001",
"avatar": null
},
"registration_code": "EST001",
"email": "estudante@exemplo.com",
"status": "FINISHED",
"entry_date": "2024-01-15",
"entry_year": "2024",
"entry_semester": "1",
"class_batch": "2024.1",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T11:00:00Z"
},
"timestamp": "2024-01-15T11:00:00Z"
}
📚 API de Atividades¶
Endpoint base: /tenant/{organization_id}/v1/activities/
⚠️ Importante: Todos os endpoints de atividades requerem o
organization_idna URL para acessar o tenant correto.
Criar Atividade¶
Cria uma nova atividade de aprendizagem.
Endpoint: POST /tenant/{organization_id}/v1/activities/
Corpo da Requisição:
{
"name": "Aula de Matemática",
"description": "Cálculo avançado e equações diferenciais",
"type": "CLASS",
"custom_type": null
}
Especificações dos Campos:
| Campo | Tipo | Obrigatório | Descrição | Validação |
|---|---|---|---|---|
name | string | Sim | Nome da atividade | Máx 200 caracteres, não vazio |
description | string | Não | Descrição da atividade | Máx 1000 caracteres |
type | string | Sim | Tipo da atividade | Veja Tipos de Atividade abaixo |
custom_type | string | Não | Tipo personalizado quando type é "OTHER" | Obrigatório quando type é "OTHER" |
Tipos de Atividade:
| Valor | Rótulo | Descrição |
|---|---|---|
CLASS | Aula | Aula tradicional |
EXERCISE | Exercício | Exercício prático |
EXAM | Prova | Avaliação formal |
ASSIGNMENT | Tarefa | Trabalho para casa |
MEETING | Reunião | Reunião ou encontro |
QUIZ | Quiz | Questionário rápido |
PRESENTATION | Apresentação | Apresentação de estudante |
WORKSHOP | Workshop | Oficina prática |
SEMINAR | Seminário | Seminário interativo |
LABORATORY | Laboratório | Sessão de laboratório |
TUTORIAL | Tutorial | Sessão de tutoria |
REVIEW | Revisão | Sessão de revisão |
OTHER | Outro | Tipo personalizado |
Resposta de Sucesso (201):
{
"success": true,
"message": "Atividade criada com sucesso",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Aula de Matemática",
"description": "Cálculo avançado e equações diferenciais",
"type": "CLASS",
"custom_type": null,
"display_type": "Aula",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"timestamp": "2024-01-15T10:30:00Z"
}
Listar Atividades¶
Recupera uma lista paginada de atividades com filtragem opcional.
Endpoint: GET /tenant/{organization_id}/v1/activities/
Parâmetros de Query:
| Parâmetro | Tipo | Obrigatório | Descrição | Exemplo |
|---|---|---|---|---|
name | string | Não | Filtrar por nome da atividade (contém) | matemática |
type | string | Não | Filtrar por tipo de atividade | CLASS, EXAM |
custom_type | string | Não | Filtrar por tipo personalizado (contém) | workshop |
description | string | Não | Filtrar por descrição (contém) | cálculo |
created_after | datetime | Não | Filtrar por criado após | 2024-01-15T10:30:00Z |
created_before | datetime | Não | Filtrar por criado antes | 2024-01-15T10:30:00Z |
search | string | Não | Buscar em nome, descrição e custom_type | matemática |
ordering | string | Não | Ordenar resultados | created_at, -created_at, name, type |
page | integer | Não | Número da página | 1 |
page_size | integer | Não | Itens por página | 20 |
Resposta de Sucesso (200):
{
"success": true,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Aula de Matemática",
"type": "CLASS",
"display_type": "Aula",
"created_at": "2024-01-15T10:30:00Z"
}
],
"count": 1,
"next": null,
"previous": null,
"timestamp": "2024-01-15T10:30:00Z"
}
Obter Detalhes da Atividade¶
Recupera informações detalhadas da atividade.
Endpoint: GET /tenant/{organization_id}/v1/activities/{id}/
Resposta de Sucesso (200):
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Aula de Matemática",
"description": "Cálculo avançado e equações diferenciais",
"type": "CLASS",
"custom_type": null,
"display_type": "Aula",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"timestamp": "2024-01-15T10:30:00Z"
}
Atualizar Atividade¶
Atualiza informações da atividade.
Endpoint: PUT /tenant/{organization_id}/v1/activities/{id}/ ou PATCH /tenant/{organization_id}/v1/activities/{id}/
Resposta de Sucesso (200):
{
"success": true,
"message": "Atividade atualizada com sucesso",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Aula de Matemática Atualizada",
"description": "Cálculo avançado e equações diferenciais",
"type": "CLASS",
"custom_type": null,
"display_type": "Aula",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T11:00:00Z"
},
"timestamp": "2024-01-15T11:00:00Z"
}
Excluir Atividade¶
Exclui uma atividade (exclusão suave).
Endpoint: DELETE /tenant/{organization_id}/v1/activities/{id}/
Resposta de Sucesso (204):
{
"success": true,
"message": "Atividade excluída com sucesso",
"timestamp": "2024-01-15T11:00:00Z"
}
Obter Tipos de Atividade¶
Recupera todos os tipos de atividade disponíveis.
Endpoint: GET /tenant/{organization_id}/v1/activities/types/
Resposta de Sucesso (200):
{
"success": true,
"message": "Tipos de atividade recuperados com sucesso",
"data": {
"types": [
{"value": "CLASS", "label": "Aula"},
{"value": "EXERCISE", "label": "Exercício"},
{"value": "EXAM", "label": "Prova"},
{"value": "ASSIGNMENT", "label": "Tarefa"},
{"value": "MEETING", "label": "Reunião"},
{"value": "QUIZ", "label": "Quiz"},
{"value": "PRESENTATION", "label": "Apresentação"},
{"value": "WORKSHOP", "label": "Workshop"},
{"value": "SEMINAR", "label": "Seminário"},
{"value": "LABORATORY", "label": "Laboratório"},
{"value": "TUTORIAL", "label": "Tutorial"},
{"value": "REVIEW", "label": "Revisão"},
{"value": "OTHER", "label": "Outro"}
]
},
"timestamp": "2024-01-15T10:30:00Z"
}
Obter Estatísticas de Atividades¶
Recupera estatísticas sobre atividades por tipo.
Endpoint: GET /tenant/{organization_id}/v1/activities/statistics/
Resposta de Sucesso (200):
{
"success": true,
"message": "Estatísticas de atividades recuperadas com sucesso",
"data": {
"statistics": [
{
"type": "CLASS",
"count": 15,
"percentage": 65.2
},
{
"type": "EXAM",
"count": 5,
"percentage": 21.7
},
{
"type": "WORKSHOP",
"count": 3,
"percentage": 13.1
}
]
},
"timestamp": "2024-01-15T10:30:00Z"
}
🎬 API de Sessões¶
Endpoint base: /tenant/{organization_id}/v1/sessions/
⚠️ Importante: Todos os endpoints de sessões requerem o
organization_idna URL para acessar o tenant correto.
Listar Sessões¶
Recupera uma lista paginada de sessões de rastreamento com opções de filtragem.
Endpoint: GET /tenant/{organization_id}/v1/sessions/
Parâmetros de Query:
| Parâmetro | Tipo | Obrigatório | Descrição | Exemplo |
|---|---|---|---|---|
student | UUID | Não | Filtrar por ID do estudante | 550e8400-e29b-41d4-a716-446655440000 |
student_registration_code | string | Não | Filtrar por código de matrícula do estudante (contém) | EST001 |
student_email | string | Não | Filtrar por email do estudante (contém) | estudante@exemplo.com |
activity | UUID | Não | Filtrar por ID da atividade | 550e8400-e29b-41d4-a716-446655440001 |
activity_name | string | Não | Filtrar por nome da atividade (contém) | matemática |
activity_type | string | Não | Filtrar por tipo da atividade | CLASS, EXAM |
started_after | datetime | Não | Filtrar por iniciado após | 2024-01-15T10:30:00Z |
started_before | datetime | Não | Filtrar por iniciado antes | 2024-01-15T10:30:00Z |
ended_after | datetime | Não | Filtrar por finalizado após | 2024-01-15T10:30:00Z |
ended_before | datetime | Não | Filtrar por finalizado antes | 2024-01-15T10:30:00Z |
is_active | boolean | Não | Filtrar por status ativo | true, false |
is_completed | boolean | Não | Filtrar por status completo | true, false |
min_duration_minutes | number | Não | Filtrar por duração mínima em minutos | 30 |
max_duration_minutes | number | Não | Filtrar por duração máxima em minutos | 120 |
search | string | Não | Buscar em código de matrícula, email do estudante ou nome da atividade | joão |
ordering | string | Não | Ordenar resultados | started_at, -started_at, ended_at, created_at |
page | integer | Não | Número da página | 1 |
page_size | integer | Não | Itens por página | 20 |
Exemplo de Requisição:
GET /tenant/550e8400-e29b-41d4-a716-446655440002/v1/sessions/?student=550e8400-e29b-41d4-a716-446655440000&is_active=true
Authorization: APIKey sk_sua_chave_api_aqui
Accept-Language: pt-br
Resposta de Sucesso (200):
{
"success": true,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"student_id": "550e8400-e29b-41d4-a716-446655440000",
"student_name": "EST001",
"activity_id": "550e8400-e29b-41d4-a716-446655440001",
"activity_name": "Aula de Matemática",
"activity_type": "CLASS",
"started_at": "2024-01-15T10:30:00Z",
"ended_at": null,
"is_active": true,
"duration_minutes": 45.5,
"display_duration": "45m 30s",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
],
"count": 1,
"next": null,
"previous": null,
"timestamp": "2024-01-15T10:30:00Z"
}
Obter Detalhes da Sessão¶
Recupera informações detalhadas da sessão.
Endpoint: GET /tenant/{organization_id}/v1/sessions/{id}/
Resposta de Sucesso (200):
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"student_id": "550e8400-e29b-41d4-a716-446655440000",
"activity_id": "550e8400-e29b-41d4-a716-446655440001",
"student_detail": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"registration_code": "EST001",
"email": "estudante@exemplo.com",
"status": "ACTIVE"
},
"activity_detail": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Aula de Matemática",
"type": "CLASS",
"description": "Cálculo avançado e equações diferenciais"
},
"started_at": "2024-01-15T10:30:00Z",
"ended_at": "2024-01-15T11:15:00Z",
"is_active": false,
"duration_seconds": 2700,
"duration_minutes": 45.0,
"display_duration": "45m 0s",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T11:15:00Z"
},
"timestamp": "2024-01-15T10:30:00Z"
}
Finalizar Sessão¶
Finaliza uma sessão de streaming ativa, definindo o timestamp de término e interrompendo automaticamente a conexão WebSocket associada.
Endpoint: POST /tenant/{organization_id}/v1/sessions/{id}/end/
Parâmetros de Caminho:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | UUID | Sim | Identificador único da sessão |
Cabeçalhos:
Exemplo de Requisição:
POST /tenant/550e8400-e29b-41d4-a716-446655440002/v1/sessions/550e8400-e29b-41d4-a716-446655440002/end/
Authorization: APIKey sk_sua_chave_api_aqui
Content-Type: application/json
Resposta de Sucesso (200):
{
"success": true,
"message": "Session ended successfully",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"student_id": "550e8400-e29b-41d4-a716-446655440000",
"activity_id": "550e8400-e29b-41d4-a716-446655440001",
"student_detail": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"registration_code": "EST001",
"email": "estudante@exemplo.com",
"status": "ACTIVE"
},
"activity_detail": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Aula de Matemática",
"type": "CLASS",
"description": "Cálculo avançado e equações diferenciais"
},
"started_at": "2024-01-15T10:30:00Z",
"ended_at": "2024-01-15T11:15:00Z",
"is_active": false,
"duration_seconds": 2700,
"duration_minutes": 45.0,
"display_duration": "45m 0s",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T11:15:00Z"
},
"timestamp": "2024-01-15T11:15:00Z"
}
Resposta de Erro - Sessão Não Ativa (400):
Resposta de Erro - Sessão Não Encontrada (404):
🔄 Comportamento da Finalização de Sessão¶
Quando uma sessão é finalizada via API, o sistema executa as seguintes ações:
- Validação de Estado: Verifica se a sessão está ativa (
ended_aténull) - Atualização do Banco: Define
ended_atcom o timestamp atual - Finalização do Billing: Aciona automaticamente o sistema de cobrança para finalizar a sessão
- Interrupção do WebSocket: A próxima tentativa de envio de frame pelo WebSocket resultará no fechamento da conexão com código
4002 - Logs Detalhados: Registra a finalização externa da sessão para auditoria
📊 Fluxo de Finalização de Sessão¶
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ API Request │───▶│ Valida Sessão │───▶│ Atualiza BD │
│ POST /sessions/ │ │ (is_active) │ │ (ended_at) │
│ {id}/end/ │ │ │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ WebSocket │◀───│ Próximo Frame │◀───│ Billing │
│ Fecha (4002) │ │ Verifica Sessão │ │ Finaliza │
│ │ │ (is_active) │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
Legenda: - Verde: Processo de finalização via API - Azul: Verificação automática no WebSocket - Vermelho: Fechamento da conexão WebSocket
⚠️ Considerações Importantes¶
- Sessões Já Finalizadas: Retorna erro 400 se a sessão já foi finalizada
- Conexão WebSocket: A conexão WebSocket será fechada automaticamente no próximo frame enviado
- Billing Automático: O sistema de cobrança é acionado automaticamente
- Idempotência: Múltiplas chamadas para a mesma sessão finalizada retornam erro 400
- Permissões: Requer permissões de colaborador ou superior para finalizar sessões
🎯 Casos de Uso¶
- Finalização Manual: Professores ou administradores podem finalizar sessões manualmente
- Controle de Tempo: Implementar limites de tempo para sessões
- Recuperação de Erro: Finalizar sessões órfãs ou com problemas
- Integração Externa: Sistemas externos podem finalizar sessões via API
📊 API de Análise de Engajamento¶
Endpoint base: /tenant/{organization_id}/v1/sessions/{session_id}/engagement/
⚠️ Importante: Todos os endpoints de análise de engajamento requerem o
organization_idna URL para acessar o tenant correto.
Obter Resumo de Engajamento¶
Recupera estatísticas agregadas de engajamento para uma sessão.
Endpoint: GET /tenant/{organization_id}/v1/sessions/{session_id}/engagement/summary/
Parâmetros de Caminho:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
session_id | UUID | Sim | Identificador único da sessão |
Resposta de Sucesso (200):
{
"session": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"duration_minutes": 45.0,
"total_frames_analyzed": 2700,
"granularity_minutes": 1.0
},
"engagement_summary": {
"mean_score": 0.725,
"mean_percentage": 72.5,
"min": {
"score": 0.452,
"percentage": 45.2
},
"max": {
"score": 0.891,
"percentage": 89.1
},
"total_periods": 45,
"high_engagement_periods": 12,
"low_engagement_periods": 3,
"high_engagement_ratio": 0.267,
"low_engagement_ratio": 0.067
},
"events_summary": {
"events": [
{
"name": "phone_use",
"total_occurrences": 2,
"occurrences_per_minute": 0.044
},
{
"name": "yawning",
"total_occurrences": 1,
"occurrences_per_minute": 0.022
},
{
"name": "drowsiness",
"total_occurrences": 0,
"occurrences_per_minute": 0.0
},
{
"name": "unfocused",
"total_occurrences": 0,
"occurrences_per_minute": 0.0
}
]
}
}
Especificações dos Campos de Resposta:
| Campo | Tipo | Descrição | Faixa |
|---|---|---|---|
session.id | UUID | Identificador da sessão | - |
session.duration_minutes | float | Duração total da sessão | > 0 |
session.total_frames_analyzed | integer | Total de frames processados | ≥ 0 |
session.granularity_minutes | float | Intervalo de agregação | 1.0 |
engagement_summary.mean_score | float | Pontuação média de engajamento | 0.0 - 1.0 |
engagement_summary.mean_percentage | float | Porcentagem média de engajamento | 0.0 - 100.0 |
engagement_summary.min.score | float | Menor pontuação de engajamento | 0.0 - 1.0 |
engagement_summary.min.percentage | float | Menor porcentagem de engajamento | 0.0 - 100.0 |
engagement_summary.max.score | float | Maior pontuação de engajamento | 0.0 - 1.0 |
engagement_summary.max.percentage | float | Maior porcentagem de engajamento | 0.0 - 100.0 |
engagement_summary.total_periods | integer | Total de períodos analisados | ≥ 0 |
engagement_summary.high_engagement_periods | integer | Períodos com engajamento ≥ 70% | ≥ 0 |
engagement_summary.low_engagement_periods | integer | Períodos com engajamento < 30% | ≥ 0 |
engagement_summary.high_engagement_ratio | float | Razão de períodos de alto engajamento | 0.0 - 1.0 |
engagement_summary.low_engagement_ratio | float | Razão de períodos de baixo engajamento | 0.0 - 1.0 |
events_summary.events[].name | string | Nome do evento | phone_use, yawning, drowsiness, unfocused |
events_summary.events[].total_occurrences | integer | Total de ocorrências do evento | ≥ 0 |
events_summary.events[].occurrences_per_minute | float | Ocorrências por minuto | ≥ 0.0 |
Obter Distribuição de Engajamento¶
Recupera dados de engajamento agregados por intervalos de minuto.
Endpoint: GET /tenant/{organization_id}/v1/sessions/{session_id}/engagement/distribution/
Resposta de Sucesso (200):
{
"session": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"granularity_minutes": 1.0
},
"timeline": [
{
"timestamp": "2024-01-15T10:30:00Z",
"frames_analyzed": 60,
"engagement": {
"score": 0.85,
"percentage": 85.0
},
"events": [
{
"name": "phone_use",
"active": false
},
{
"name": "yawning",
"active": false
},
{
"name": "drowsiness",
"active": false
},
{
"name": "unfocused",
"active": false
}
]
},
{
"timestamp": "2024-01-15T10:31:00Z",
"frames_analyzed": 60,
"engagement": {
"score": 0.72,
"percentage": 72.0
},
"events": [
{
"name": "phone_use",
"active": true
},
{
"name": "yawning",
"active": false
},
{
"name": "drowsiness",
"active": false
},
{
"name": "unfocused",
"active": false
}
]
}
]
}
Especificações dos Campos de Timeline:
| Campo | Tipo | Descrição | Faixa |
|---|---|---|---|
session.id | UUID | Identificador da sessão | - |
session.granularity_minutes | float | Intervalo de agregação | 1.0 |
timeline[].timestamp | datetime | Hora de início do intervalo de minuto | ISO 8601 |
timeline[].frames_analyzed | integer | Frames analisados neste minuto | ≥ 0 |
timeline[].engagement.score | float | Pontuação de engajamento para este minuto | 0.0 - 1.0 |
timeline[].engagement.percentage | float | Porcentagem de engajamento para este minuto | 0.0 - 100.0 |
timeline[].events[].name | string | Nome do evento | phone_use, yawning, drowsiness, unfocused |
timeline[].events[].active | boolean | Se o evento ocorreu neste minuto | true/false |
😊 API de Análise de Emoção¶
Endpoint base: /tenant/{organization_id}/v1/sessions/{session_id}/emotion/
⚠️ Importante: Todos os endpoints de análise de emoção requerem o
organization_idna URL para acessar o tenant correto.
Obter Resumo de Emoção¶
Recupera estatísticas agregadas de emoção para uma sessão.
Endpoint: GET /tenant/{organization_id}/v1/sessions/{session_id}/emotion/summary/
Parâmetros de Caminho:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
session_id | UUID | Sim | Identificador único da sessão |
Resposta de Sucesso (200):
{
"session": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"duration_minutes": 45.0,
"total_frames_analyzed": 2700,
"granularity_minutes": 1.0
},
"emotion_summary": {
"dominant_emotion": {
"name": "HAPPY",
"score": 0.65,
"percentage": 65.0
},
"distribution": [
{
"name": "HAPPY",
"score": 0.65,
"percentage": 65.0
},
{
"name": "NEUTRAL",
"score": 0.25,
"percentage": 25.0
},
{
"name": "SAD",
"score": 0.08,
"percentage": 8.0
},
{
"name": "ANGRY",
"score": 0.02,
"percentage": 2.0
}
]
}
}
Especificações dos Campos de Resposta:
| Campo | Tipo | Descrição | Faixa |
|---|---|---|---|
session.id | UUID | Identificador da sessão | - |
session.duration_minutes | float | Duração total da sessão | > 0 |
session.total_frames_analyzed | integer | Total de frames processados | ≥ 0 |
session.granularity_minutes | float | Intervalo de agregação | 1.0 |
emotion_summary.dominant_emotion.name | string | Emoção dominante detectada | HAPPY, NEUTRAL, SAD, ANGRY, SURPRISED, FEAR, DISGUST, NOT_DETECTED |
emotion_summary.dominant_emotion.score | float | Pontuação da emoção dominante | 0.0 - 1.0 |
emotion_summary.dominant_emotion.percentage | float | Porcentagem da emoção dominante | 0.0 - 100.0 |
emotion_summary.distribution[].name | string | Nome da emoção | HAPPY, NEUTRAL, SAD, ANGRY, SURPRISED, FEAR, DISGUST, NOT_DETECTED |
emotion_summary.distribution[].score | float | Pontuação da emoção | 0.0 - 1.0 |
emotion_summary.distribution[].percentage | float | Porcentagem da emoção | 0.0 - 100.0 |
Obter Distribuição de Emoção¶
Recupera dados de emoção agregados por intervalos de minuto.
Endpoint: GET /tenant/{organization_id}/v1/sessions/{session_id}/emotion/distribution/
Resposta de Sucesso (200):
{
"session": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"duration_minutes": 45.0,
"total_frames_analyzed": 2700,
"granularity_minutes": 1.0
},
"timeline": [
{
"timestamp": "2024-01-15T10:30:00Z",
"frames_analyzed": 60,
"emotion": {
"dominant_emotion": {
"name": "HAPPY",
"score": 0.75,
"percentage": 75.0
},
"distribution": [
{
"name": "HAPPY",
"score": 0.75,
"percentage": 75.0
},
{
"name": "NEUTRAL",
"score": 0.20,
"percentage": 20.0
},
{
"name": "SAD",
"score": 0.05,
"percentage": 5.0
}
]
}
},
{
"timestamp": "2024-01-15T10:31:00Z",
"frames_analyzed": 60,
"emotion": {
"dominant_emotion": {
"name": "NEUTRAL",
"score": 0.50,
"percentage": 50.0
},
"distribution": [
{
"name": "NEUTRAL",
"score": 0.50,
"percentage": 50.0
},
{
"name": "HAPPY",
"score": 0.40,
"percentage": 40.0
},
{
"name": "SAD",
"score": 0.10,
"percentage": 10.0
}
]
}
}
]
}
Especificações dos Campos de Timeline:
| Campo | Tipo | Descrição | Faixa |
|---|---|---|---|
timestamp | datetime | Hora de início do intervalo de minuto | ISO 8601 |
frames_analyzed | integer | Frames analisados neste minuto | ≥ 0 |
emotion.dominant_emotion | object | Emoção dominante neste minuto | - |
emotion.distribution | array | Distribuição de todas as emoções neste minuto | - |
🧠 API de Análise Cognitiva¶
Endpoint base: /tenant/{organization_id}/v1/sessions/{session_id}/cognitive/
⚠️ Importante: Todos os endpoints de análise cognitiva requerem o
organization_idna URL para acessar o tenant correto.
Obter Resumo Cognitivo¶
Recupera estatísticas agregadas de presença cognitiva para uma sessão.
Endpoint: GET /tenant/{organization_id}/v1/sessions/{session_id}/cognitive/summary/
Parâmetros de Caminho:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
session_id | UUID | Sim | Identificador único da sessão |
Resposta de Sucesso (200):
{
"session": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"duration_minutes": 45.0,
"total_frames_analyzed": 2700
},
"cognitive_presence_summary": {
"dominant_state": {
"name": "full_presence",
"score": 0.55,
"percentage": 55.0
},
"distribution": [
{
"name": "full_presence",
"score": 0.55,
"percentage": 55.0
},
{
"name": "semi_presence",
"score": 0.30,
"percentage": 30.0
},
{
"name": "absent",
"score": 0.15,
"percentage": 15.0
}
]
}
}
Especificações dos Campos de Resposta:
| Campo | Tipo | Descrição | Faixa |
|---|---|---|---|
session.id | UUID | Identificador da sessão | - |
session.duration_minutes | float | Duração total da sessão | > 0 |
session.total_frames_analyzed | integer | Total de frames processados | ≥ 0 |
cognitive_presence_summary.dominant_state.name | string | Estado cognitivo dominante | absent, semi_presence, full_presence |
cognitive_presence_summary.dominant_state.score | float | Pontuação do estado dominante | 0.0 - 1.0 |
cognitive_presence_summary.dominant_state.percentage | float | Porcentagem do estado dominante | 0.0 - 100.0 |
cognitive_presence_summary.distribution[].name | string | Nome do estado cognitivo | absent, semi_presence, full_presence |
cognitive_presence_summary.distribution[].score | float | Pontuação do estado | 0.0 - 1.0 |
cognitive_presence_summary.distribution[].percentage | float | Porcentagem do estado | 0.0 - 100.0 |
Obter Distribuição Cognitiva¶
Recupera dados de presença cognitiva agregados por intervalos de minuto.
Endpoint: GET /tenant/{organization_id}/v1/sessions/{session_id}/cognitive/distribution/
Resposta de Sucesso (200):
{
"session": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"granularity_minutes": 1.0
},
"timeline": [
{
"timestamp": "2024-01-15T10:30:00Z",
"frames_analyzed": 60,
"cognitive_presence": {
"dominant_state": {
"name": "full_presence",
"score": 0.65,
"percentage": 65.0
},
"distribution": [
{
"name": "full_presence",
"score": 0.65,
"percentage": 65.0
},
{
"name": "semi_presence",
"score": 0.25,
"percentage": 25.0
},
{
"name": "absent",
"score": 0.10,
"percentage": 10.0
}
]
}
},
{
"timestamp": "2024-01-15T10:31:00Z",
"frames_analyzed": 60,
"cognitive_presence": {
"dominant_state": {
"name": "semi_presence",
"score": 0.55,
"percentage": 55.0
},
"distribution": [
{
"name": "semi_presence",
"score": 0.55,
"percentage": 55.0
},
{
"name": "full_presence",
"score": 0.30,
"percentage": 30.0
},
{
"name": "absent",
"score": 0.15,
"percentage": 15.0
}
]
}
}
]
}
Especificações dos Campos de Timeline:
| Campo | Tipo | Descrição | Faixa |
|---|---|---|---|
session.id | UUID | Identificador da sessão | - |
session.granularity_minutes | float | Intervalo de agregação | 1.0 |
timeline[].timestamp | datetime | Hora de início do intervalo de minuto | ISO 8601 |
timeline[].frames_analyzed | integer | Frames analisados neste minuto | ≥ 0 |
timeline[].cognitive_presence.dominant_state.name | string | Estado cognitivo dominante neste minuto | absent, semi_presence, full_presence |
timeline[].cognitive_presence.dominant_state.score | float | Pontuação do estado dominante | 0.0 - 1.0 |
timeline[].cognitive_presence.dominant_state.percentage | float | Porcentagem do estado dominante | 0.0 - 100.0 |
timeline[].cognitive_presence.distribution[].name | string | Nome do estado cognitivo | absent, semi_presence, full_presence |
timeline[].cognitive_presence.distribution[].score | float | Pontuação do estado | 0.0 - 1.0 |
timeline[].cognitive_presence.distribution[].percentage | float | Porcentagem do estado | 0.0 - 100.0 |
❌ Códigos de Erro¶
Códigos de Status HTTP¶
| Código | Descrição | Quando Ocorre |
|---|---|---|
200 | OK | Requisições GET, PUT, PATCH bem-sucedidas |
201 | Criado | Requisições POST bem-sucedidas |
204 | Sem Conteúdo | Requisições DELETE bem-sucedidas |
400 | Requisição Inválida | Formato de requisição inválido ou erros de validação |
401 | Não Autorizado | Chave API ausente ou inválida |
403 | Proibido | Chave API não tem permissões necessárias |
404 | Não Encontrado | Recurso não existe |
429 | Muitas Requisições | Limite de taxa excedido |
500 | Erro Interno do Servidor | Erro do lado do servidor |
Formato de Resposta de Erro¶
{
"success": false,
"message": "Descrição do erro",
"errors": {
"nome_do_campo": ["Mensagem de erro específica"]
},
"timestamp": "2024-01-15T10:30:00Z"
}
Cenários Comuns de Erro¶
Erros de Validação (400)¶
{
"success": false,
"message": "Erro de validação ocorreu",
"errors": {
"email": ["Insira um endereço de email válido."],
"registration_code": ["Este campo é obrigatório."],
"status": ["\"INVALID\" não é uma escolha válida."]
},
"timestamp": "2024-01-15T10:30:00Z"
}
Erros de Autenticação (401)¶
Erros de Permissão (403)¶
{
"success": false,
"message": "Você não tem permissão para acessar esta sessão",
"timestamp": "2024-01-15T10:30:00Z"
}
Erros de Não Encontrado (404)¶
⚡ Limites de Taxa¶
Cabeçalhos de Limite de Taxa¶
Todas as respostas incluem informações de limite de taxa:
Categorias de Limite de Taxa¶
| Categoria de Endpoint | Requisições por Hora | Limite de Rajada |
|---|---|---|
| APIs Padrão | 1000 | 100 por minuto |
| Análise de Engajamento | 100 | 10 por minuto |
| Análise de Emoção | 100 | 10 por minuto |
| Análise Cognitiva | 100 | 10 por minuto |
| Conexões WebSocket | 10 simultâneas | - |
Resposta de Limite de Taxa Excedido (429)¶
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1642248000
Retry-After: 3600
{
"success": false,
"message": "Limite de taxa excedido. Tente novamente mais tarde.",
"timestamp": "2024-01-15T10:30:00Z"
}
Melhores Práticas para Limite de Taxa¶
- Implementar Backoff Exponencial: Aguarde progressivamente mais tempo entre tentativas
- Cache de Respostas: Armazene dados acessados frequentemente localmente
- Requisições em Lote: Combine múltiplas operações quando possível
- Monitorar Cabeçalhos: Verifique
X-RateLimit-Remainingpara evitar atingir limites
📝 Tipos de Dados¶
Formato UUID¶
Todos os IDs são UUIDs no formato: 550e8400-e29b-41d4-a716-446655440000
Formato de Data/Hora¶
Todos os timestamps usam formato ISO 8601: 2024-01-15T10:30:00Z
Formato de Paginação¶
{
"data": [...],
"count": 100,
"next": "https://api.sadionline.com.br/v1/students/?page=2",
"previous": null
}
Valores Booleanos¶
true/false(minúsculas)- Usados para flags como
is_active
Construído com ❤️ pelo Instituto Anexo