Pular para conteúdo

📚 API Reference

Referência completa da API SADIONLINE

Este documento fornece especificações técnicas detalhadas para todos os endpoints da API SADIONLINE.


📋 Índice

  1. Autenticação
  2. API de Estudantes
  3. API de Atividades
  4. API de Sessões
  5. Listar Sessões
  6. Obter Detalhes da Sessão
  7. Finalizar Sessão
  8. API de Análise de Engajamento
  9. Códigos de Erro
  10. Limites de Taxa

🔐 Autenticação

Todas as requisições da API requerem autenticação usando uma chave API no cabeçalho Authorization:

Authorization: APIKey sk_sua_chave_api_aqui

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:

https://api.sadionline.com.br/tenant/{organization_id}/v1/{endpoint}

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_id na 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:

Authorization: APIKey sk_sua_chave_api_aqui
Content-Type: application/json
Accept-Language: pt-br

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):

{
  "status": "INACTIVE"
}

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:

{
  "status": "FINISHED"
}

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_id na 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_id na 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:

Authorization: APIKey sk_sua_chave_api_aqui
Content-Type: application/json
Accept-Language: pt-br

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):

{
  "success": false,
  "message": "Session is not active",
  "timestamp": "2024-01-15T11:15:00Z"
}

Resposta de Erro - Sessão Não Encontrada (404):

{
  "success": false,
  "message": "Session not found",
  "timestamp": "2024-01-15T11:15:00Z"
}

🔄 Comportamento da Finalização de Sessão

Quando uma sessão é finalizada via API, o sistema executa as seguintes ações:

  1. Validação de Estado: Verifica se a sessão está ativa (ended_at é null)
  2. Atualização do Banco: Define ended_at com o timestamp atual
  3. Finalização do Billing: Aciona automaticamente o sistema de cobrança para finalizar a sessão
  4. Interrupção do WebSocket: A próxima tentativa de envio de frame pelo WebSocket resultará no fechamento da conexão com código 4002
  5. 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_id na 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_id na 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_id na 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)

{
  "success": false,
  "message": "Chave API inválida",
  "timestamp": "2024-01-15T10:30:00Z"
}

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)

{
  "success": false,
  "message": "Estudante não encontrado",
  "timestamp": "2024-01-15T10:30:00Z"
}

⚡ Limites de Taxa

Cabeçalhos de Limite de Taxa

Todas as respostas incluem informações de limite de taxa:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1642248000

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

  1. Implementar Backoff Exponencial: Aguarde progressivamente mais tempo entre tentativas
  2. Cache de Respostas: Armazene dados acessados frequentemente localmente
  3. Requisições em Lote: Combine múltiplas operações quando possível
  4. Monitorar Cabeçalhos: Verifique X-RateLimit-Remaining para 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

Referência da API Completa 📚
Construído com ❤️ pelo Instituto Anexo