{
    "openapi": "3.1.0",
    "info": {
        "title": "API EstudioLMS",
        "version": "1.0.0",
        "summary": "API REST da sua escola no EstudioLMS.",
        "description": "Cada escola atende no proprio endereco. O acesso e feito por **token de\nintegracao**, criado pelo administrador da escola em *Integracoes > API*.\n\n## Autenticacao\n\nEnvie o token no cabecalho, em toda chamada:\n\n```\nAuthorization: Bearer elms_live_...\n```\n\nO token **nunca** vai na URL nem no corpo: nesses lugares ele fica gravado\nno registro do servidor, no historico do navegador e no cabecalho `Referer`.\nUma chamada que mande o token fora do cabecalho recebe `400`.\n\n## Nao existe ambiente de testes\n\n**Atencao:** nao ha sandbox. O token atende o ambiente real da escola, e\ntoda escrita vale de verdade. Comece com um token somente de leitura e, para\ntestar escrita, use um curso ou usuario criado para esse fim.\n\n## Como saber o que mudou\n\nNao ha webhooks. Para sincronizar, consulte as listas com o filtro\n`updated_since`, guardando a data da ultima consulta. Registro excluido sai\ndas listas: para saber que ele saiu, consulte-o pelo id.\n\n## Escrita\n\nToda escrita recebe `Content-Type: application/json` com um objeto JSON.\nCampo desconhecido e **recusado** (`422 unknown-field`), nunca ignorado.\nConteudo criado pela API nasce **despublicado**: publicar e uma acao\nexplicita. HTML recebido passa por filtro com lista permitida.\n\nEnvie `Idempotency-Key` em toda escrita: repetir a chamada com a mesma\nchave (por exemplo, apos um timeout) devolve a resposta guardada, sem\nexecutar de novo. No cadastro de usuario ela e obrigatoria.\n\nQuando uma regra da escola impede a operacao (excluir curso com\nmatricula, publicar curso sem preco), a resposta e `409 conflict` com um\n`reason` estavel para tratar no seu codigo.\n\n## Limites\n\n60 requisicoes por minuto e 10.000 por dia por token; 300 por minuto\nsomando todos os tokens da escola. Toda resposta traz `X-RateLimit-Limit`,\n`X-RateLimit-Remaining` e `X-RateLimit-Reset`. Ao estourar, a resposta e\n`429` com `Retry-After`.\n\nCorpo de no maximo 1 MB por requisicao.\n\n## Erros\n\nTodo erro sai em `application/problem+json` (RFC 9457), com um `request_id`.\nGuarde esse valor: e por ele que o suporte da escola encontra a chamada na\nauditoria.\n",
        "contact": {
            "name": "Suporte EstudioLMS",
            "url": "https://lmsestudio.com.br"
        }
    },
    "servers": [
        {
            "url": "https://{escola}/api/v1",
            "description": "Endereco da escola (subdominio em lmsestudio.com ou dominio proprio)",
            "variables": {
                "escola": {
                    "default": "minhaescola.lmsestudio.com",
                    "description": "Dominio da sua escola"
                }
            }
        }
    ],
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "tags": [
        {
            "name": "Conexao",
            "description": "Conferir o token e descobrir o que ele pode fazer."
        },
        {
            "name": "Cursos",
            "description": "Cursos, categorias, modulos e aulas."
        },
        {
            "name": "Pessoas",
            "description": "Alunos, professores, turmas e matriculas."
        },
        {
            "name": "Financeiro",
            "description": "Pedidos, assinaturas e relatorios. Somente consulta — a API nao vende, nao cobra e nao estorna."
        },
        {
            "name": "Desempenho",
            "description": "Progresso, certificados e emblemas."
        },
        {
            "name": "Referencia",
            "description": "Listas de valores para interpretar as outras respostas. Qualquer token valido."
        }
    ],
    "paths": {
        "/me": {
            "get": {
                "tags": [
                    "Conexao"
                ],
                "operationId": "getMe",
                "summary": "Dados do token em uso",
                "description": "Atende **qualquer token valido**, sem exigir permissao de modulo: e com\nesta chamada que se confere a conexao antes de escrever a integracao.\n\nDevolve duas listas de permissoes. `granted` e o que esta gravado no\ntoken, como a tela mostra. `effective` e tudo o que o token satisfaz de\nfato, incluindo o que vem por nivel — um token com `courses.delete`\ntambem le e escreve cursos, e so a segunda lista mostra isso.\n",
                "responses": {
                    "200": {
                        "description": "Token valido.",
                        "headers": {
                            "X-Request-Id": {
                                "$ref": "#/components/headers/XRequestId"
                            },
                            "X-RateLimit-Limit": {
                                "$ref": "#/components/headers/XRateLimitLimit"
                            },
                            "X-RateLimit-Remaining": {
                                "$ref": "#/components/headers/XRateLimitRemaining"
                            },
                            "X-RateLimit-Reset": {
                                "$ref": "#/components/headers/XRateLimitReset"
                            }
                        },
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Me"
                                        }
                                    }
                                },
                                "examples": {
                                    "leituraAcademica": {
                                        "summary": "Token de leitura academica",
                                        "value": {
                                            "data": {
                                                "token": {
                                                    "name": "ERP - sincroniza alunos",
                                                    "purpose": "Importar matriculas do ERP",
                                                    "masked": "elms_live_...Qw2r",
                                                    "last_four": "Qw2r",
                                                    "expires_at": "2027-01-27T10:00:00-03:00",
                                                    "last_used_at": "2026-10-29T14:30:00-03:00",
                                                    "rate_limit_per_minute": 60,
                                                    "ip_restricted": true
                                                },
                                                "school": {
                                                    "id": "minhaescola",
                                                    "plan": "Profissional"
                                                },
                                                "permissions": {
                                                    "granted": [
                                                        "courses.read",
                                                        "users.read"
                                                    ],
                                                    "effective": [
                                                        "courses.read",
                                                        "users.read"
                                                    ]
                                                },
                                                "api": {
                                                    "version": "v1",
                                                    "phase": 0
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "$ref": "#/components/responses/TokenNoLugarErrado"
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemTls"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    },
                    "503": {
                        "$ref": "#/components/responses/Indisponivel"
                    }
                }
            }
        },
        "/courses": {
            "get": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "listCourses",
                "summary": "Lista os cursos da escola",
                "description": "Exige a permissao **Cursos: Leitura** (`courses.read`).\n\nOs campos `description`, `programmatic_content` e `prerequisites` so\naparecem com a permissao **Conteudo das aulas**\n(`special.lesson_content`). Sem ela eles nao vem — nao e erro, e a\nregra. Nao assuma que existem.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "description": "Situacao do curso.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "published",
                                "draft"
                            ]
                        }
                    },
                    {
                        "name": "category_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "instructor_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "description": "Busca por nome ou resumo.",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "name",
                                "created_at",
                                "updated_at",
                                "published_at"
                            ]
                        }
                    },
                    {
                        "name": "dir",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "asc",
                                "desc"
                            ],
                            "default": "asc"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada de cursos.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Course"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "createCourse",
                "summary": "Cria curso",
                "description": "Exige **Cursos: Escrita** (`courses.write`).\n\nO curso nasce **despublicado**. A API nao define preco, imagem nem campos\nHotmart: configure o preco na tela antes de publicar.\n\nSem `instructor_id`, o instrutor e quem criou o token. Os campos de HTML\npassam por filtro (perfil de aula); `name` e `short_description` viram texto\npuro.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CourseCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Curso criado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Course"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}": {
            "get": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "getCourse",
                "summary": "Um curso",
                "description": "Exige **Cursos: Leitura** (`courses.read`).",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "O curso.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Course"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "updateCourse",
                "summary": "Altera curso",
                "description": "Exige **Cursos: Escrita** (`courses.write`). Envie so os campos a mudar.\nSituacao muda pelas acoes `publish`/`unpublish`, nao por aqui.\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CourseUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Curso alterado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Course"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "deleteCourse",
                "summary": "Exclui curso",
                "description": "Exige **Cursos: Exclusao** (`courses.delete`), que pede lista de IPs no token.\n\nExclusao logica. Recusada com `409` (`reason: has_enrollments`) se houver\nmatricula — despublique o curso para tira-lo da vitrine.\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Excluido."
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/course-categories": {
            "get": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "listCourseCategories",
                "summary": "Lista as categorias de curso",
                "description": "Exige **Cursos: Leitura** (`courses.read`) — a mesma permissao dos\ncursos: quem le curso precisa ler a categoria dele.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    },
                    {
                        "name": "parent_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "name",
                                "created_at",
                                "updated_at"
                            ]
                        }
                    },
                    {
                        "name": "dir",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "asc",
                                "desc"
                            ],
                            "default": "asc"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada de categorias.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/CourseCategory"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "createCourseCategory",
                "summary": "Cria categoria de curso",
                "description": "Exige **Cursos: Escrita** (`courses.write`).\n\nA categoria nasce **despublicada** (`status: draft`). Subcategoria herda o\nidioma do pai. No maximo 3 niveis.\n\n`description` passa por filtro de HTML (perfil basico: sem imagem, tabela\nou video).\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CourseCategoryCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Categoria criada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CourseCategory"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/course-categories/{category}": {
            "get": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "getCourseCategory",
                "summary": "Uma categoria",
                "description": "Exige **Cursos: Leitura** (`courses.read`).",
                "parameters": [
                    {
                        "name": "category",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A categoria.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CourseCategory"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "updateCourseCategory",
                "summary": "Altera categoria de curso",
                "description": "Exige **Cursos: Escrita** (`courses.write`). Envie so os campos a mudar.\n\n`status` publica ou despublica a categoria — e leva junto as subcategorias,\ncomo na tela. O slug nao muda com o nome (ele esta em links ja publicados).\n",
                "parameters": [
                    {
                        "name": "category",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CourseCategoryUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Categoria alterada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/CourseCategory"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "deleteCourseCategory",
                "summary": "Exclui categoria de curso",
                "description": "Exige **Cursos: Exclusao** (`courses.delete`), que pede lista de IPs no token.\n\nExclusao logica, junto com as subcategorias. Recusada com `409`\n(`reason: has_courses`) se houver curso na categoria ou em descendente.\n",
                "parameters": [
                    {
                        "name": "category",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Excluida."
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/modules": {
            "get": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "listModules",
                "summary": "Modulos de um curso",
                "description": "Exige a permissao `lessons.read`.",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Module"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "createModule",
                "summary": "Cria modulo",
                "description": "Exige **Aulas: Escrita** (`lessons.write`). O modulo vai para o fim do curso,\n**despublicado**. Nome unico no curso.\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ModuleWrite"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Modulo criado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Module"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/modules/{module}/lessons": {
            "get": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "listLessons",
                "summary": "Aulas de um modulo",
                "description": "Exige `lessons.read`. O campo `content` so aparece com `special.lesson_content`.",
                "parameters": [
                    {
                        "name": "module",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Lesson"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "createLesson",
                "summary": "Cria aula sem arquivo",
                "description": "Exige **Aulas: Escrita** (`lessons.write`).\n\nTipos aceitos: `text`, `link`, `video` (YouTube/Vimeo), `code`, `separator`\ne `youtubelive`. Aulas com arquivo ficam para uma fase posterior. A aula vai\npara o fim do modulo, **despublicada**.\n\nHTML (`content`, `description`) passa por filtro com lista permitida. URLs so\n`https`; a API nunca acessa a URL informada (a duracao do video vem em\n`duration_seconds`, ou fica zero).\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "module",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/LessonCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Aula criada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Lesson"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/lessons/{lesson}": {
            "get": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "getLesson",
                "summary": "Uma aula",
                "description": "Exige a permissao `lessons.read`.",
                "parameters": [
                    {
                        "name": "lesson",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Lesson"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "updateLesson",
                "summary": "Altera aula",
                "description": "Exige **Aulas: Escrita** (`lessons.write`). O tipo nao muda; envie os campos\ndo tipo da aula. Aula de tipo com arquivo ou questionario: `409`\n(`reason: lesson_type_not_supported`).\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "lesson",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/LessonUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aula alterada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Lesson"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "deleteLesson",
                "summary": "Exclui aula",
                "description": "Exige **Aulas: Exclusao** (`lessons.delete`), que pede lista de IPs no token.\nSo os tipos sem arquivo; os demais: `409` (`reason: lesson_type_not_supported`).\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "lesson",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Excluida."
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/quizzes": {
            "get": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "listQuizzes",
                "summary": "Quizzes de um curso (so metadados)",
                "description": "Exige `lessons.read`. So metadados: o gabarito nunca sai na v1. Paginado.",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Lesson"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/users": {
            "get": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "listUsers",
                "summary": "Lista alunos e professores",
                "description": "Exige `users.read`. CPF, telefone e endereco so com `special.personal_data`. Papeis administrativos nao aparecem.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/User"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "createUser",
                "summary": "Cadastra aluno ou professor",
                "description": "Exige **Usuarios: Escrita** (`users.write`) e o cabecalho **`Idempotency-Key`**\n(obrigatorio aqui).\n\nO papel (`student` ou `teacher`) e fixo na criacao. A API **nao recebe\nsenha**: o usuario recebe por e-mail o link para definir a dele\n(`send_invite`, padrao `true`). O resultado do envio vem em\n`meta.invite`; o cadastro vale mesmo se o e-mail falhar.\n\n`cpf` e `address` exigem a permissao **Dados pessoais**\n(`special.personal_data`) — sem ela, `403`. E-mail ja usado (inclusive por\nusuario excluido): `422`.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/UserCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Usuario cadastrado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/User"
                                        },
                                        "meta": {
                                            "type": "object",
                                            "properties": {
                                                "invite": {
                                                    "$ref": "#/components/schemas/InviteResult"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "409": {
                        "$ref": "#/components/responses/ChaveEmConflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/users/{user}": {
            "get": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "getUser",
                "summary": "Um aluno ou professor",
                "description": "Exige a permissao `users.read`.",
                "parameters": [
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/User"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "updateUser",
                "summary": "Altera aluno ou professor",
                "description": "Exige **Usuarios: Escrita** (`users.write`). Altera `name`, `cpf` e `address`\n(estes dois com **Dados pessoais**).\n\n`email`, `role`, `status` e `password` sao **recusados com `422`**, com o\nmotivo: o e-mail nao muda pela API, o papel e fixo, a situacao muda pelas\nacoes `activate`/`deactivate`.\n",
                "parameters": [
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/UserUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Usuario alterado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/User"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "deleteUser",
                "summary": "Exclui aluno ou professor",
                "description": "Exige **Usuarios: Exclusao** (`users.delete`), que pede lista de IPs no token.\n\nExclusao logica. Recusada com `409` (`reason: has_enrollments`) se houver\nmatricula — desative o usuario para bloquear o acesso.\n",
                "parameters": [
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Excluido."
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/groups": {
            "get": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "listGroups",
                "summary": "Lista as turmas",
                "description": "Exige a permissao `classes.read`.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Group"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "createGroup",
                "summary": "Cria turma",
                "description": "Exige **Turmas: Escrita** (`classes.write`). Nome e codigo unicos. Nasce\n`draft`, salvo `status: published`. Turma nao da acesso a curso.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/GroupWrite"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Turma criada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Group"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/groups/{group}": {
            "get": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "getGroup",
                "summary": "Uma turma",
                "description": "Exige a permissao `classes.read`.",
                "parameters": [
                    {
                        "name": "group",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Group"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "updateGroup",
                "summary": "Altera turma",
                "description": "Exige **Turmas: Escrita** (`classes.write`). Envie so os campos a mudar.\n",
                "parameters": [
                    {
                        "name": "group",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/GroupWrite"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Turma alterada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Group"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "deleteGroup",
                "summary": "Exclui turma",
                "description": "Exige **Turmas: Exclusao** (`classes.delete`), que pede lista de IPs no token.\nExclusao logica; os vinculos de membro ficam guardados.\n",
                "parameters": [
                    {
                        "name": "group",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Excluida."
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/groups/{group}/members": {
            "get": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "listGroupMembers",
                "summary": "Membros de uma turma",
                "description": "Exige a permissao `classes.read`.",
                "parameters": [
                    {
                        "name": "group",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/User"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "addGroupMembers",
                "summary": "Inclui membros na turma",
                "description": "Exige **Turmas: Escrita** (`classes.write`). Ate 100 ids por chamada. Quem ja\ne membro nao e duplicado. Id que nao e aluno ou professor visivel volta em\n`skipped` com `reason: not_found`.\n",
                "parameters": [
                    {
                        "name": "group",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/MembersAdd"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Resultado da inclusao.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/MembersResult"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/enrollments": {
            "get": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "listEnrollments",
                "summary": "Lista as matriculas",
                "description": "Exige a permissao `enrollments.read`.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    },
                    {
                        "name": "user_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "course_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "active",
                                "expired",
                                "inactive"
                            ]
                        }
                    },
                    {
                        "name": "source",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "api",
                                "admin",
                                "free",
                                "purchase"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Enrollment"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "createEnrollment",
                "summary": "Concede acesso a um curso (sem cobranca)",
                "description": "Exige **Matriculas: Escrita** (`enrollments.write`). `Idempotency-Key`\nobrigatoria.\n\nMatricula **administrativa, sem cobranca**: nao gera venda, nao soma\nreceita. Informe `access_days` (a partir de hoje) **ou** `access_until`\n(ultimo dia, incluido). O acesso termina as 23:59:59 do ultimo dia, no\nfuso da escola. O curso precisa ter um plano configurado no painel.\n\nSe o aluno ja teve acesso a este curso (expirado, cancelado), a mesma\nmatricula e renovada (`meta.outcome: renewed`) e o progresso dele e\nmantido.\n\nRecusas com `409` e `reason`: `already_active` (o aluno ja tem acesso;\nnada muda), `pending_order` (ha pedido do curso aguardando pagamento),\n`missing_plan`, `concurrent_request` (tente de novo com a mesma chave).\nLimite de alunos do plano: `422 plan-limit-reached`.\n\n`notify` (padrao `true`) envia ao aluno o aviso padrao de matricula.\n",
                "parameters": [
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "description": "Obrigatoria. Ver o parametro idempotencyKey.",
                        "schema": {
                            "type": "string",
                            "pattern": "^[A-Za-z0-9_-]{8,128}$"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/EnrollmentCreate"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "Acesso concedido.",
                        "headers": {
                            "Location": {
                                "schema": {
                                    "type": "string"
                                }
                            }
                        },
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Enrollment"
                                        },
                                        "meta": {
                                            "type": "object",
                                            "properties": {
                                                "outcome": {
                                                    "type": "string",
                                                    "enum": [
                                                        "created",
                                                        "renewed"
                                                    ]
                                                },
                                                "notified": {
                                                    "type": "boolean",
                                                    "description": "Aviso disparado. Falha de e-mail nao desfaz a matricula."
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/enrollments/bulk": {
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "createEnrollmentsBulk",
                "summary": "Concede acesso em lote (ate 100)",
                "description": "Exige **Matriculas: Escrita** (`enrollments.write`). `Idempotency-Key`\nobrigatoria.\n\nFormato invalido recusa a chamada inteira (`422`, apontando o item).\nRecusa de negocio de um item nao para os demais: ele sai em `skipped`\ncom o motivo — `user_not_found`, `course_not_found`, `already_active`,\n`pending_order`, `missing_plan`, `plan_limit_reached`, `failed`.\n\n`notify` e `false` por padrao: o aviso e enviado na hora, e cem avisos\nseguidos podem estourar o tempo da chamada.\n",
                "parameters": [
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "description": "Obrigatoria. Ver o parametro idempotencyKey.",
                        "schema": {
                            "type": "string",
                            "pattern": "^[A-Za-z0-9_-]{8,128}$"
                        }
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/EnrollmentBulk"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Resultado por item.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/EnrollmentBulkResult"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/enrollments/{enrollment}": {
            "get": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "getEnrollment",
                "summary": "Uma matricula",
                "description": "Exige a permissao `enrollments.read`.",
                "parameters": [
                    {
                        "name": "enrollment",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Enrollment"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "updateEnrollment",
                "summary": "Altera o fim do acesso",
                "description": "Exige **Matriculas: Escrita** (`enrollments.write`). So o fim do acesso,\ne so de matricula concedida pela API (`source: api`); as demais\nrespondem `409 reason: not_api_enrollment`. Matricula expirada volta a\nvaler com uma data futura. Revogada: `409 reason: revoked`.\n",
                "parameters": [
                    {
                        "name": "enrollment",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/EnrollmentUpdate"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Matricula alterada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Enrollment"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/enrollments/{enrollment}/revoke": {
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "revokeEnrollment",
                "summary": "Revoga acesso concedido pela API",
                "description": "Exige **Matriculas: Exclusao** (`enrollments.delete`). Sem corpo.\n\nCancela so o que a API concedeu (`source: api`); acesso por compra,\ncurso gratuito ou matricula do painel nunca e revogado pela API\n(`409 reason: not_api_enrollment`). Depois de revogar, o acesso e\nrecalculado pelos outros pedidos do aluno no curso: se ele tem uma\ncompra paga e valida, a matricula continua `active`, agora com\n`source: purchase`. Repetir: `409 reason: already_revoked`.\n",
                "parameters": [
                    {
                        "name": "enrollment",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A matricula como ficou.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Enrollment"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/users/{user}/progress": {
            "get": {
                "tags": [
                    "Desempenho"
                ],
                "operationId": "getUserProgress",
                "summary": "Progresso de um aluno",
                "description": "Exige `performance.read`. `lessons_completed` so aparece se a escola registrar conclusao por aula. Paginado.",
                "parameters": [
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Progress"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/progress": {
            "get": {
                "tags": [
                    "Desempenho"
                ],
                "operationId": "getCourseProgress",
                "summary": "Progresso dos alunos de um curso",
                "description": "Exige a permissao `performance.read`.",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Progress"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/certificates": {
            "get": {
                "tags": [
                    "Desempenho"
                ],
                "operationId": "listCertificates",
                "summary": "Certificados emitidos",
                "description": "Exige a permissao `certificates.read`.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Certificate"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/certificates/{certificate}": {
            "get": {
                "tags": [
                    "Desempenho"
                ],
                "operationId": "getCertificate",
                "summary": "Um certificado",
                "description": "Exige a permissao `certificates.read`.",
                "parameters": [
                    {
                        "name": "certificate",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Certificate"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/users/{user}/badges": {
            "get": {
                "tags": [
                    "Desempenho"
                ],
                "operationId": "listUserBadges",
                "summary": "Emblemas de um aluno",
                "description": "Exige a permissao `gamification.read`.",
                "parameters": [
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Badge"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/reference/lesson-types": {
            "get": {
                "tags": [
                    "Referencia"
                ],
                "operationId": "listLessonTypes",
                "summary": "Tipos de aula",
                "description": "Atende qualquer token valido.",
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reference"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/reference/course-levels": {
            "get": {
                "tags": [
                    "Referencia"
                ],
                "operationId": "listCourseLevels",
                "summary": "Niveis de curso",
                "description": "Atende qualquer token valido.",
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reference"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/reference/course-types": {
            "get": {
                "tags": [
                    "Referencia"
                ],
                "operationId": "listCourseTypes",
                "summary": "Tipos de curso",
                "description": "Atende qualquer token valido.",
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Reference"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/publish": {
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "publishCourse",
                "summary": "Publica curso",
                "description": "Exige **Cursos: Escrita** (`courses.write`). Sem corpo.\n\nRecusada com `409` (`reason: missing_price`) se o preco ou a duracao ainda\nnao foram configurados na tela.\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Curso publicado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Course"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/unpublish": {
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "unpublishCourse",
                "summary": "Despublica curso",
                "description": "Exige **Cursos: Escrita** (`courses.write`). Sem corpo. Quem ja esta\nmatriculado continua com acesso.\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Curso despublicado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Course"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/modules/reorder": {
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "reorderModules",
                "summary": "Reordena os modulos",
                "description": "Exige **Aulas: Escrita** (`lessons.write`). Envie **todos** os ids dos modulos\ndo curso, na ordem desejada, uma vez cada. Lista parcial e recusada com `409`\n(`reason: order_mismatch`).\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/Reorder"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Modulos na nova ordem.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Module"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/modules/{module}": {
            "patch": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "updateModule",
                "summary": "Renomeia modulo",
                "description": "Exige **Aulas: Escrita** (`lessons.write`). O slug acompanha o nome.\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "module",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/ModuleWrite"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Modulo alterado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Module"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "deleteModule",
                "summary": "Exclui modulo",
                "description": "Exige **Aulas: Exclusao** (`lessons.delete`), que pede lista de IPs no token.\nExclusao logica do modulo **e das aulas dele**.\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "module",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Excluido."
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/modules/{module}/publish": {
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "publishModule",
                "summary": "Publica modulo",
                "description": "Exige **Aulas: Escrita** (`lessons.write`). Sem corpo.\n\n**Leva junto todas as aulas do modulo**, como na tela: publica tambem as aulas\nque estavam em outra situacao.\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "module",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Modulo alterado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Module"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/modules/{module}/unpublish": {
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "unpublishModule",
                "summary": "Despublica modulo",
                "description": "Exige **Aulas: Escrita** (`lessons.write`). Sem corpo.\n\n**Leva junto todas as aulas do modulo**, como na tela: despublica tambem as aulas\nque estavam em outra situacao.\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "module",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Modulo alterado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Module"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/modules/{module}/lessons/reorder": {
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "reorderLessons",
                "summary": "Reordena as aulas de um modulo",
                "description": "Exige **Aulas: Escrita** (`lessons.write`). Envie **todos** os ids das aulas\ndo modulo, na ordem desejada. Lista parcial: `409` (`reason: order_mismatch`).\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "module",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/Reorder"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aulas na nova ordem.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Lesson"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/lessons/{lesson}/publish": {
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "publishLesson",
                "summary": "Publica aula",
                "description": "Exige **Aulas: Escrita** (`lessons.write`). Sem corpo. Vale para qualquer\ntipo, menos questionario (`409`, `reason: quiz_visibility_managed`).\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "lesson",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Aula alterada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Lesson"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/courses/{course}/lessons/{lesson}/unpublish": {
            "post": {
                "tags": [
                    "Cursos"
                ],
                "operationId": "unpublishLesson",
                "summary": "Despublica aula",
                "description": "Exige **Aulas: Escrita** (`lessons.write`). Sem corpo. Vale para qualquer\ntipo, menos questionario (`409`, `reason: quiz_visibility_managed`).\n",
                "parameters": [
                    {
                        "name": "course",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "lesson",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Aula alterada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Lesson"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/users/{user}/deactivate": {
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "deactivateUser",
                "summary": "Desativa aluno ou professor",
                "description": "Exige **Usuarios: Escrita** (`users.write`). Sem corpo. O usuario deixa de conseguir entrar. Ja inativo: `200`, sem mudanca.\n",
                "parameters": [
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Usuario alterado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/User"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/users/{user}/activate": {
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "activateUser",
                "summary": "Ativa aluno ou professor",
                "description": "Exige **Usuarios: Escrita** (`users.write`). Sem corpo. Ja ativo: `200`, sem mudanca.\n",
                "parameters": [
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Usuario alterado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/User"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/users/{user}/send-password-reset": {
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "sendPasswordReset",
                "summary": "Envia o link de definir senha",
                "description": "Exige **Usuarios: Escrita** (`users.write`). Sem corpo.\n\nEnvia ao proprio usuario o link padrao de \"esqueci minha senha\". A API\nnunca ve nem define a senha. Usuario inativo ou pedido repetido em menos de\num minuto: `409` (`reason: user_inactive` / `recently_sent`). Falha do\nservidor de e-mail: `502`, com `error_ref`.\n",
                "parameters": [
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "202": {
                        "description": "Link enviado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "object",
                                            "properties": {
                                                "sent": {
                                                    "type": "boolean"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/users/{user}/restore": {
            "post": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "restoreUser",
                "summary": "Restaura aluno ou professor excluido",
                "description": "Exige **Usuarios: Exclusao** (`users.delete`). Sem corpo. `404` se o usuario\nnao estiver excluido.\n",
                "parameters": [
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Usuario restaurado.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/User"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "409": {
                        "$ref": "#/components/responses/Conflito"
                    },
                    "415": {
                        "$ref": "#/components/responses/TipoNaoSuportado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/groups/{group}/members/{user}": {
            "delete": {
                "tags": [
                    "Pessoas"
                ],
                "operationId": "removeGroupMember",
                "summary": "Tira membro da turma",
                "description": "Exige **Turmas: Escrita** (`classes.write`). `404` se o usuario nao for membro.\n",
                "parameters": [
                    {
                        "name": "group",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "user",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "$ref": "#/components/parameters/idempotencyKey"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Removido."
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/orders": {
            "get": {
                "tags": [
                    "Financeiro"
                ],
                "operationId": "listOrders",
                "summary": "Lista os pedidos de curso",
                "description": "Exige **Vendas** (`sales.read`). Somente consulta. Codigo de transacao do\ngateway, boleto e dados de cartao nunca saem.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    },
                    {
                        "name": "user_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "course_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "pending",
                                "in_analysis",
                                "paid",
                                "available",
                                "disputed",
                                "refunded",
                                "canceled",
                                "expired"
                            ]
                        }
                    },
                    {
                        "name": "gateway",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "api",
                                "admin",
                                "free",
                                "pagarme",
                                "paypal",
                                "pagseguro",
                                "hotmart",
                                "paghiper"
                            ]
                        }
                    },
                    {
                        "name": "created_from",
                        "in": "query",
                        "description": "Criados a partir deste instante (ISO 8601 com fuso).",
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "created_to",
                        "in": "query",
                        "description": "Criados antes deste instante (exclusivo; ISO 8601 com fuso).",
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Order"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/orders/{order}": {
            "get": {
                "tags": [
                    "Financeiro"
                ],
                "operationId": "getOrder",
                "summary": "Um pedido",
                "description": "Exige a permissao `sales.read`.",
                "parameters": [
                    {
                        "name": "order",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Order"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/subscriptions": {
            "get": {
                "tags": [
                    "Financeiro"
                ],
                "operationId": "listSubscriptions",
                "summary": "Lista as assinaturas de alunos",
                "description": "Exige a permissao `subscriptions.read`. As cobrancas saem so no detalhe.",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/page"
                    },
                    {
                        "$ref": "#/components/parameters/perPage"
                    },
                    {
                        "$ref": "#/components/parameters/updatedSince"
                    },
                    {
                        "name": "user_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "plan_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "active",
                                "pending",
                                "suspended",
                                "canceled"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Lista paginada.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Pagination"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "data": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/Subscription"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/subscriptions/{subscription}": {
            "get": {
                "tags": [
                    "Financeiro"
                ],
                "operationId": "getSubscription",
                "summary": "Uma assinatura, com as cobrancas",
                "description": "Exige a permissao `subscriptions.read`. Ate 120 cobrancas, das mais recentes.",
                "parameters": [
                    {
                        "name": "subscription",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "O registro.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Subscription"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        },
        "/reports/{report}": {
            "get": {
                "tags": [
                    "Financeiro"
                ],
                "operationId": "getReport",
                "summary": "Relatorio agregado",
                "description": "Exige **Relatorios** (`reports.read`). Lista fechada:\n\n- `sales`: pedidos criados no periodo, por status; pagos (status pago,\n  disponivel ou expirado, como o relatorio do painel) com totais, por\n  gateway e por curso;\n- `enrollments`: por curso, matriculas novas e concluidas no periodo, e\n  a situacao atual (ativas, expiradas, inativas);\n- `certificates`: certificados emitidos no periodo, por curso.\n\n`from` e `to` obrigatorios (AAAA-MM-DD, os dois incluidos, fuso da\nescola), com ate 366 dias. Nenhum relatorio traz dado de aluno.\n",
                "parameters": [
                    {
                        "name": "report",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "sales",
                                "enrollments",
                                "certificates"
                            ]
                        }
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "course_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "O relatorio.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Report"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/NaoAutenticado"
                    },
                    "403": {
                        "$ref": "#/components/responses/SemPermissao"
                    },
                    "404": {
                        "$ref": "#/components/responses/NaoEncontrado"
                    },
                    "422": {
                        "$ref": "#/components/responses/DadosInvalidos"
                    },
                    "429": {
                        "$ref": "#/components/responses/LimiteAlcancado"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "description": "Token da escola, criado em *Integracoes > API*. Comeca com\n`elms_live_`. Aparece uma unica vez, na criacao: guarde-o em cofre de\nsegredos. Se perder, rotacione — nao ha como recuperar o valor.\n"
            }
        },
        "headers": {
            "XRequestId": {
                "description": "Identificador desta chamada. Cite-o ao procurar o suporte.",
                "schema": {
                    "type": "string",
                    "format": "uuid"
                }
            },
            "XRateLimitLimit": {
                "description": "Limite de requisicoes por minuto deste token.",
                "schema": {
                    "type": "integer"
                }
            },
            "XRateLimitRemaining": {
                "description": "Quantas requisicoes restam na janela atual.",
                "schema": {
                    "type": "integer"
                }
            },
            "XRateLimitReset": {
                "description": "Momento em que a janela reinicia (epoch, em segundos).",
                "schema": {
                    "type": "integer"
                }
            },
            "RetryAfter": {
                "description": "Segundos a esperar antes de tentar de novo.",
                "schema": {
                    "type": "integer"
                }
            },
            "IdempotentReplay": {
                "description": "`true` quando a resposta foi devolvida de uma chamada anterior com a\nmesma `Idempotency-Key`, sem executar nada desta vez.\n",
                "schema": {
                    "type": "string",
                    "enum": [
                        "true"
                    ]
                }
            }
        },
        "parameters": {
            "page": {
                "name": "page",
                "in": "query",
                "description": "Pagina, a partir de 1.",
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "default": 1
                }
            },
            "perPage": {
                "name": "per_page",
                "in": "query",
                "description": "Itens por pagina.",
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 25
                }
            },
            "updatedSince": {
                "name": "updated_since",
                "in": "query",
                "description": "So os registros alterados a partir desta data (ISO 8601). E o meio de\nsincronizacao incremental: nao ha webhooks.\n",
                "schema": {
                    "type": "string",
                    "format": "date-time"
                }
            },
            "idempotencyKey": {
                "name": "Idempotency-Key",
                "in": "header",
                "description": "Chave de 8 a 128 caracteres (letras, numeros, hifen e sublinhado; um\nUUID serve) que identifica a operacao. Repetir a chamada com a mesma\nchave devolve a resposta guardada, sem executar de novo — e o que evita\nduplicata quando a resposta se perde num timeout.\n\nUse uma chave nova para cada operacao: a mesma chave com um pedido\ndiferente recebe `409`.\n",
                "schema": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{8,128}$"
                }
            }
        },
        "schemas": {
            "Me": {
                "type": "object",
                "required": [
                    "token",
                    "school",
                    "permissions",
                    "api"
                ],
                "properties": {
                    "token": {
                        "type": "object",
                        "required": [
                            "name",
                            "purpose",
                            "masked",
                            "last_four",
                            "expires_at",
                            "rate_limit_per_minute",
                            "ip_restricted"
                        ],
                        "properties": {
                            "name": {
                                "type": "string",
                                "description": "Nome dado ao token na criacao."
                            },
                            "purpose": {
                                "type": "string",
                                "description": "Finalidade declarada."
                            },
                            "masked": {
                                "type": "string",
                                "description": "Identificacao segura do token. Nunca o valor completo.",
                                "examples": [
                                    "elms_live_...Qw2r"
                                ]
                            },
                            "last_four": {
                                "type": "string",
                                "description": "Ultimos quatro caracteres, para conferir na tela."
                            },
                            "expires_at": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time",
                                "description": "Fim da validade. Todo token tem validade."
                            },
                            "last_used_at": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "format": "date-time",
                                "description": "Ultimo uso. Atualizado no maximo uma vez por minuto."
                            },
                            "rate_limit_per_minute": {
                                "type": "integer",
                                "description": "Limite por minuto deste token."
                            },
                            "ip_restricted": {
                                "type": "boolean",
                                "description": "Indica **se** ha restricao de IP, nao quais sao os IPs. A lista\nnao e devolvida de proposito.\n"
                            }
                        }
                    },
                    "school": {
                        "type": "object",
                        "required": [
                            "id"
                        ],
                        "properties": {
                            "id": {
                                "type": "string",
                                "description": "Identificador da escola."
                            },
                            "plan": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "Nome do plano da escola."
                            }
                        }
                    },
                    "permissions": {
                        "type": "object",
                        "required": [
                            "granted",
                            "effective"
                        ],
                        "properties": {
                            "granted": {
                                "type": "array",
                                "description": "Permissoes gravadas no token.",
                                "items": {
                                    "$ref": "#/components/schemas/Permission"
                                }
                            },
                            "effective": {
                                "type": "array",
                                "description": "Tudo o que o token satisfaz, com os niveis resolvidos. Use esta\nlista para decidir o que a integracao pode chamar.\n",
                                "items": {
                                    "$ref": "#/components/schemas/Permission"
                                }
                            }
                        }
                    },
                    "api": {
                        "type": "object",
                        "required": [
                            "version"
                        ],
                        "properties": {
                            "version": {
                                "type": "string",
                                "examples": [
                                    "v1"
                                ]
                            },
                            "phase": {
                                "type": "integer",
                                "description": "Fase de entrega em vigor. Informativo."
                            }
                        }
                    }
                }
            },
            "Course": {
                "type": "object",
                "description": "Curso da escola. **Lista fixa de campos:** o que nao esta aqui nao sai,\ninclusive coluna acrescentada ao banco depois.\n",
                "required": [
                    "id",
                    "name",
                    "status"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "slug": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "short_description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "HTML do curso. **So com `special.lesson_content`** — sem a permissao o campo nao aparece."
                    },
                    "programmatic_content": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "So com `special.lesson_content`."
                    },
                    "prerequisites": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "So com `special.lesson_content`."
                    },
                    "category": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "properties": {
                            "id": {
                                "type": "integer"
                            },
                            "name": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "instructor": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "So `id` e `name`, como na vitrine publica.",
                        "properties": {
                            "id": {
                                "type": "integer"
                            },
                            "name": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "level": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "Nome traduzido pelo `Accept-Language`.",
                        "properties": {
                            "id": {
                                "type": "integer"
                            },
                            "name": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "type": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "properties": {
                            "id": {
                                "type": "integer"
                            },
                            "name": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "course_load": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Carga horaria em horas. 0 = nao informada (o banco nunca guarda nulo)."
                    },
                    "is_free": {
                        "type": "boolean"
                    },
                    "purpose": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "sales",
                            "internal",
                            null
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "published",
                            "draft"
                        ]
                    },
                    "published_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "CourseCategory": {
                "type": "object",
                "required": [
                    "id",
                    "name"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "slug": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "parent_id": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Categoria pai, quando houver (0 = raiz)."
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "published",
                            "draft"
                        ]
                    },
                    "language": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "pt",
                            "en",
                            "es",
                            null
                        ],
                        "description": "Idioma da categoria. Subcategoria herda o do pai."
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Module": {
                "type": "object",
                "required": [
                    "id",
                    "course_id",
                    "name",
                    "status"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "course_id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "slug": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "position": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "published",
                            "draft"
                        ]
                    },
                    "published_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Lesson": {
                "type": "object",
                "description": "Aula. O campo `content` so aparece com `special.lesson_content` — sem a\npermissao ele nao vem, e isso nao e erro.\n",
                "required": [
                    "id",
                    "course_id",
                    "type",
                    "status"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "course_id": {
                        "type": "integer"
                    },
                    "module_id": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "name": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "slug": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "type": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "integer"
                            },
                            "name": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "Identificador estavel do tipo (video, text, quiz...)."
                            }
                        }
                    },
                    "position": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "is_free": {
                        "type": "boolean",
                        "description": "Aula liberada como previa gratuita."
                    },
                    "counts_for_average": {
                        "type": "boolean",
                        "description": "Entra na media do curso."
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "published",
                            "draft"
                        ]
                    },
                    "content": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Corpo da aula. So com `special.lesson_content`."
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "User": {
                "type": "object",
                "description": "Aluno ou professor. `cpf`, `phone` e `address` so aparecem com\n`special.personal_data`, que exige lista de IPs no token.\n\nPapeis administrativos (admin, owner, superadmin) nao sao devolvidos.\n",
                "required": [
                    "id",
                    "name",
                    "email",
                    "status"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "email": {
                        "type": "string",
                        "format": "email"
                    },
                    "role": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "student",
                            "teacher",
                            null
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "active",
                            "inactive"
                        ]
                    },
                    "cpf": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "So com `special.personal_data`."
                    },
                    "phone": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "So com `special.personal_data`."
                    },
                    "address": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "So com `special.personal_data`.",
                        "properties": {
                            "zip_code": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "street": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "number": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "complement": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "neighborhood": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "city": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "state": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Group": {
                "type": "object",
                "required": [
                    "id",
                    "name",
                    "status"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "slug": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "code": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "published",
                            "draft"
                        ]
                    },
                    "members_count": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Enrollment": {
                "type": "object",
                "description": "Acesso de um aluno a um curso. Nada de financeiro aparece aqui: vendas e\nassinaturas sao outra permissao.\n",
                "required": [
                    "id",
                    "user_id",
                    "course_id",
                    "status"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "user_id": {
                        "type": "integer"
                    },
                    "course_id": {
                        "type": "integer"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "active",
                            "expired",
                            "inactive"
                        ],
                        "description": "`active`: o aluno abre o curso agora. `expired`: o acesso acabou pelo\nprazo. `inactive`: sem acesso por outro motivo (aguardando pagamento,\ncancelada, estornada).\n"
                    },
                    "source": {
                        "type": "string",
                        "enum": [
                            "api",
                            "admin",
                            "free",
                            "purchase",
                            "unknown"
                        ],
                        "description": "Origem do acesso. So `api` aceita alteracao de prazo e revogacao pela\nAPI.\n"
                    },
                    "starts_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "ends_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "is_free": {
                        "type": "boolean"
                    },
                    "completed": {
                        "type": "boolean"
                    },
                    "completed_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "EnrollmentCreate": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                    "user_id",
                    "course_id"
                ],
                "description": "Informe `access_days` ou `access_until` — exatamente um.",
                "properties": {
                    "user_id": {
                        "type": "integer",
                        "description": "Usuario com papel de aluno."
                    },
                    "course_id": {
                        "type": "integer"
                    },
                    "access_days": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 3650,
                        "description": "Dias de acesso a partir de hoje."
                    },
                    "access_until": {
                        "type": "string",
                        "format": "date",
                        "description": "Ultimo dia de acesso, incluido. Hoje ou depois, ate 3650 dias."
                    },
                    "notify": {
                        "type": "boolean",
                        "default": true
                    }
                }
            },
            "EnrollmentBulk": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                    "items"
                ],
                "properties": {
                    "items": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "object",
                            "additionalProperties": false,
                            "required": [
                                "user_id",
                                "course_id"
                            ],
                            "properties": {
                                "user_id": {
                                    "type": "integer"
                                },
                                "course_id": {
                                    "type": "integer"
                                },
                                "access_days": {
                                    "type": "integer",
                                    "minimum": 1,
                                    "maximum": 3650
                                },
                                "access_until": {
                                    "type": "string",
                                    "format": "date"
                                }
                            }
                        }
                    },
                    "notify": {
                        "type": "boolean",
                        "default": false
                    }
                }
            },
            "EnrollmentBulkResult": {
                "type": "object",
                "properties": {
                    "created": {
                        "type": "integer"
                    },
                    "renewed": {
                        "type": "integer"
                    },
                    "results": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "index": {
                                    "type": "integer",
                                    "description": "Posicao do item no pedido, a partir de 0."
                                },
                                "user_id": {
                                    "type": "integer"
                                },
                                "course_id": {
                                    "type": "integer"
                                },
                                "enrollment_id": {
                                    "type": "integer"
                                },
                                "outcome": {
                                    "type": "string",
                                    "enum": [
                                        "created",
                                        "renewed"
                                    ]
                                },
                                "notified": {
                                    "type": "boolean"
                                }
                            }
                        }
                    },
                    "skipped": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "index": {
                                    "type": "integer"
                                },
                                "user_id": {
                                    "type": "integer"
                                },
                                "course_id": {
                                    "type": "integer"
                                },
                                "reason": {
                                    "type": "string",
                                    "enum": [
                                        "user_not_found",
                                        "course_not_found",
                                        "already_active",
                                        "pending_order",
                                        "missing_plan",
                                        "plan_limit_reached",
                                        "failed"
                                    ]
                                }
                            }
                        }
                    }
                }
            },
            "EnrollmentUpdate": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                    "access_until"
                ],
                "properties": {
                    "access_until": {
                        "type": "string",
                        "format": "date",
                        "description": "Novo ultimo dia de acesso, incluido."
                    }
                }
            },
            "Money": {
                "type": [
                    "string",
                    "null"
                ],
                "pattern": "^-?[0-9]+\\.[0-9]{2}$",
                "description": "Valor decimal em texto, com duas casas e ponto (`\"149.90\"`)."
            },
            "Order": {
                "type": "object",
                "description": "Pedido de curso. Somente consulta. O codigo da transacao no gateway, o\nboleto e os dados de cartao nunca saem.\n",
                "required": [
                    "id",
                    "user_id",
                    "course_id",
                    "gateway",
                    "status",
                    "amounts"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "user_id": {
                        "type": "integer"
                    },
                    "course_id": {
                        "type": "integer"
                    },
                    "gateway": {
                        "type": "string",
                        "enum": [
                            "api",
                            "admin",
                            "free",
                            "pagarme",
                            "paypal",
                            "pagseguro",
                            "hotmart",
                            "paghiper",
                            "other"
                        ],
                        "description": "`api` e `admin` sao matriculas sem cobranca; `free`, curso gratuito."
                    },
                    "payment_method": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "credit_card",
                            "boleto",
                            "pix",
                            "other",
                            null
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "pending",
                            "in_analysis",
                            "paid",
                            "available",
                            "disputed",
                            "refunded",
                            "canceled",
                            "expired",
                            "unknown"
                        ]
                    },
                    "installments": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "amounts": {
                        "type": "object",
                        "description": "Valores como registrados. A taxa pode vir zerada quando o gateway nao a informou.",
                        "properties": {
                            "gross": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "discount": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "fee": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "extra": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "shipping": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "installment_interest": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "net": {
                                "$ref": "#/components/schemas/Money"
                            }
                        }
                    },
                    "coupon": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "properties": {
                            "code": {
                                "type": "string"
                            },
                            "title": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "discount": {
                                "$ref": "#/components/schemas/Money"
                            }
                        }
                    },
                    "access_starts_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "access_ends_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Subscription": {
                "type": "object",
                "description": "Assinatura de aluno. Codigo de pagamento e cartao nunca saem.",
                "required": [
                    "id",
                    "user_id",
                    "status"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "user_id": {
                        "type": "integer"
                    },
                    "plan": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "integer"
                            },
                            "title": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    },
                    "period_days": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Periodicidade da cobranca, em dias."
                    },
                    "gateway": {
                        "type": "string"
                    },
                    "payment_method": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "credit_card",
                            "boleto",
                            "pix",
                            null
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "active",
                            "pending",
                            "suspended",
                            "canceled",
                            "unknown"
                        ]
                    },
                    "amounts": {
                        "type": "object",
                        "properties": {
                            "gross": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "discount": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "fee": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "extra": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "net": {
                                "$ref": "#/components/schemas/Money"
                            }
                        }
                    },
                    "charges": {
                        "type": "array",
                        "description": "So no detalhe.",
                        "items": {
                            "$ref": "#/components/schemas/SubscriptionCharge"
                        }
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "SubscriptionCharge": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "number": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Numero da cobranca na assinatura."
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "scheduled",
                            "paid",
                            "failed",
                            "issued",
                            "cancel_requested",
                            "canceled",
                            "canceled_unpaid",
                            "unknown"
                        ],
                        "description": "`failed`: cartao recusado, sera tentado de novo. `issued`: boleto emitido, nao pago."
                    },
                    "payment_method": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "due_date": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date"
                    },
                    "paid_date": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date"
                    },
                    "attempts": {
                        "type": "integer"
                    },
                    "amounts": {
                        "type": "object",
                        "properties": {
                            "gross": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "discount": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "fee": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "extra": {
                                "$ref": "#/components/schemas/Money"
                            },
                            "net": {
                                "$ref": "#/components/schemas/Money"
                            }
                        }
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "updated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Report": {
                "type": "object",
                "required": [
                    "report",
                    "from",
                    "to",
                    "totals",
                    "by_course"
                ],
                "description": "`totals` e os itens de `by_course` variam por relatorio. `sales`:\n`orders_by_status` e `paid` (orders, gross, discount, fee, shipping, net),\nmais `by_gateway`. `enrollments`: new_in_period, completed_in_period,\nactive_now, expired_now, inactive_now, completed_total. `certificates`:\nissued.\n",
                "properties": {
                    "report": {
                        "type": "string",
                        "enum": [
                            "sales",
                            "enrollments",
                            "certificates"
                        ]
                    },
                    "from": {
                        "type": "string",
                        "format": "date"
                    },
                    "to": {
                        "type": "string",
                        "format": "date"
                    },
                    "course_id": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "totals": {
                        "type": "object"
                    },
                    "by_gateway": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        }
                    },
                    "by_course": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        }
                    }
                }
            },
            "Progress": {
                "type": "object",
                "description": "Progresso de um aluno num curso. A conclusao e a nota vem da regra unica\nda escola, a mesma que o aluno ve no painel.\n",
                "required": [
                    "user_id",
                    "course_id",
                    "completed"
                ],
                "properties": {
                    "user_id": {
                        "type": "integer"
                    },
                    "course_id": {
                        "type": "integer"
                    },
                    "lessons_total": {
                        "type": "integer",
                        "description": "Aulas do curso, sem contar separadores."
                    },
                    "lessons_completed": {
                        "type": "integer",
                        "description": "So aparece quando a escola registra conclusao por aula. Ausente\nsignifica \"o sistema nao guarda esse dado\", nao \"zero aulas vistas\".\n"
                    },
                    "completed": {
                        "type": "boolean"
                    },
                    "completed_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "enrolled_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Certificate": {
                "type": "object",
                "required": [
                    "id",
                    "user_id",
                    "course_id"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "user_id": {
                        "type": "integer"
                    },
                    "course_id": {
                        "type": "integer"
                    },
                    "issued_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    },
                    "validation_code": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Codigo que a pessoa digita na pagina de validacao da escola."
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Badge": {
                "type": "object",
                "required": [
                    "id",
                    "user_id",
                    "badge_id"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "user_id": {
                        "type": "integer"
                    },
                    "course_id": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "badge_id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "value": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "acquired_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "format": "date-time"
                    }
                }
            },
            "Reference": {
                "type": "object",
                "description": "Item de uma lista de referencia (nivel, tipo de curso, tipo de aula).",
                "required": [
                    "id"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "is_separator": {
                        "type": "boolean",
                        "description": "So nos tipos de aula."
                    }
                }
            },
            "Permission": {
                "type": "string",
                "description": "Permissao do catalogo. Os niveis sao cumulativos dentro do modulo:\n`delete` inclui `write`, que inclui `read`.\n",
                "enum": [
                    "courses.read",
                    "courses.write",
                    "courses.delete",
                    "lessons.read",
                    "lessons.write",
                    "lessons.delete",
                    "users.read",
                    "users.write",
                    "users.delete",
                    "classes.read",
                    "classes.write",
                    "classes.delete",
                    "enrollments.read",
                    "enrollments.write",
                    "enrollments.delete",
                    "performance.read",
                    "certificates.read",
                    "gamification.read",
                    "sales.read",
                    "subscriptions.read",
                    "reports.read",
                    "special.personal_data",
                    "special.lesson_content"
                ]
            },
            "Problem": {
                "type": "object",
                "description": "Erro no formato RFC 9457.",
                "required": [
                    "type",
                    "title",
                    "status"
                ],
                "properties": {
                    "type": {
                        "type": "string",
                        "description": "Identificador estavel do tipo de erro.",
                        "enum": [
                            "unauthenticated",
                            "forbidden",
                            "not-found",
                            "method-not-allowed",
                            "validation-failed",
                            "unknown-field",
                            "rate-limited",
                            "payload-too-large",
                            "tls-required",
                            "api-disabled",
                            "school-unavailable",
                            "service-misconfigured",
                            "token-in-query-string",
                            "idempotency-key-conflict",
                            "plan-limit-reached",
                            "server-error",
                            "conflict",
                            "unsupported-media-type"
                        ]
                    },
                    "title": {
                        "type": "string",
                        "description": "Frase curta e estavel."
                    },
                    "status": {
                        "type": "integer",
                        "description": "Mesmo codigo HTTP da resposta."
                    },
                    "detail": {
                        "type": "string",
                        "description": "Explicacao, quando houver algo util a dizer."
                    },
                    "errors": {
                        "type": "object",
                        "description": "Erros por campo, na validacao.",
                        "additionalProperties": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    },
                    "reason": {
                        "type": "string",
                        "description": "So no `409 conflict`: codigo estavel do motivo, para tratar no\ncodigo. Valores atuais: `has_courses`, `has_enrollments`,\n`missing_price`, `order_mismatch`, `category_cycle`,\n`parent_not_found`, `max_depth`, `lesson_type_not_supported`,\n`quiz_visibility_managed`, `recently_sent`, `user_inactive` e os\n`policy_*` da politica de gestao de usuarios.\n"
                    },
                    "request_id": {
                        "type": "string",
                        "format": "uuid",
                        "description": "Identificador da chamada, para o suporte."
                    }
                }
            },
            "CourseCategoryCreate": {
                "type": "object",
                "required": [
                    "name"
                ],
                "additionalProperties": false,
                "properties": {
                    "name": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 80,
                        "description": "Unico entre todas as categorias."
                    },
                    "parent_id": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "0 ou ausente = categoria raiz."
                    },
                    "language": {
                        "type": "string",
                        "enum": [
                            "pt",
                            "en",
                            "es"
                        ],
                        "default": "pt",
                        "description": "So na raiz; subcategoria herda do pai."
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "HTML, filtrado (perfil basico)."
                    }
                }
            },
            "CourseCategoryUpdate": {
                "type": "object",
                "minProperties": 1,
                "additionalProperties": false,
                "properties": {
                    "name": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 80
                    },
                    "parent_id": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "language": {
                        "type": "string",
                        "enum": [
                            "pt",
                            "en",
                            "es"
                        ]
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "published",
                            "draft"
                        ]
                    }
                }
            },
            "CourseCreate": {
                "type": "object",
                "required": [
                    "name",
                    "short_description",
                    "category_id",
                    "level_id",
                    "type_id"
                ],
                "additionalProperties": false,
                "properties": {
                    "name": {
                        "type": "string",
                        "minLength": 3,
                        "maxLength": 255
                    },
                    "short_description": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Texto puro."
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "HTML, filtrado (perfil de aula)."
                    },
                    "programmatic_content": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "HTML, filtrado."
                    },
                    "prerequisites": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "HTML, filtrado."
                    },
                    "category_id": {
                        "type": "integer"
                    },
                    "instructor_id": {
                        "type": "integer",
                        "description": "Professor ativo. Ausente = quem criou o token."
                    },
                    "level_id": {
                        "type": "integer",
                        "description": "Ver /reference/course-levels."
                    },
                    "type_id": {
                        "type": "integer",
                        "description": "Ver /reference/course-types."
                    },
                    "certificate_requirement": {
                        "type": "string",
                        "enum": [
                            "none",
                            "all_lessons"
                        ],
                        "default": "none"
                    },
                    "course_load": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "minimum": 0,
                        "maximum": 100000,
                        "default": 0,
                        "description": "Carga horaria em horas. Ausente ou null = nao informada, gravada como 0."
                    },
                    "purpose": {
                        "type": "string",
                        "enum": [
                            "sales",
                            "internal"
                        ],
                        "default": "sales"
                    }
                }
            },
            "CourseUpdate": {
                "type": "object",
                "minProperties": 1,
                "additionalProperties": false,
                "description": "Os mesmos campos de CourseCreate, todos opcionais.",
                "properties": {
                    "name": {
                        "type": "string",
                        "minLength": 3,
                        "maxLength": 255
                    },
                    "short_description": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "programmatic_content": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "prerequisites": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "category_id": {
                        "type": "integer"
                    },
                    "instructor_id": {
                        "type": "integer"
                    },
                    "level_id": {
                        "type": "integer"
                    },
                    "type_id": {
                        "type": "integer"
                    },
                    "certificate_requirement": {
                        "type": "string",
                        "enum": [
                            "none",
                            "all_lessons"
                        ]
                    },
                    "course_load": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "minimum": 0,
                        "maximum": 100000,
                        "description": "null = nao informada, gravada como 0."
                    },
                    "purpose": {
                        "type": "string",
                        "enum": [
                            "sales",
                            "internal"
                        ]
                    }
                }
            },
            "ModuleWrite": {
                "type": "object",
                "required": [
                    "name"
                ],
                "additionalProperties": false,
                "properties": {
                    "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 255,
                        "description": "Unico entre os modulos do curso."
                    }
                }
            },
            "Reorder": {
                "type": "object",
                "required": [
                    "order"
                ],
                "additionalProperties": false,
                "properties": {
                    "order": {
                        "type": "array",
                        "description": "Todos os ids, na ordem desejada, uma vez cada.",
                        "items": {
                            "type": "integer"
                        }
                    }
                }
            },
            "LessonCreate": {
                "type": "object",
                "required": [
                    "type",
                    "title"
                ],
                "description": "Campos por tipo:\n\n| type | obrigatorios | opcionais |\n|---|---|---|\n| `text` | `content` (HTML) | — |\n| `link` | `url` (https) | `description` (HTML) |\n| `video` | `url` (YouTube ou Vimeo, https) | `duration_seconds` |\n| `code` | `code` (texto; exibido como codigo, nunca executado) | `description` (HTML) |\n| `separator` | — | — |\n| `youtubelive` | `youtube_id` (11 caracteres), `event_date` (ISO 8601 com fuso) | `description` (HTML) |\n\nCampo de outro tipo e recusado como desconhecido.\n",
                "properties": {
                    "type": {
                        "type": "string",
                        "enum": [
                            "text",
                            "link",
                            "video",
                            "code",
                            "separator",
                            "youtubelive"
                        ]
                    },
                    "title": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 255
                    },
                    "content": {
                        "type": "string"
                    },
                    "url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "duration_seconds": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "minimum": 0,
                        "maximum": 86400
                    },
                    "code": {
                        "type": "string"
                    },
                    "youtube_id": {
                        "type": "string",
                        "pattern": "^[A-Za-z0-9_-]{11}$"
                    },
                    "event_date": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "LessonUpdate": {
                "type": "object",
                "minProperties": 1,
                "description": "Os campos de LessonCreate do tipo da aula, todos opcionais, sem `type`.",
                "properties": {
                    "title": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 255
                    },
                    "content": {
                        "type": "string"
                    },
                    "url": {
                        "type": "string",
                        "format": "uri"
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "duration_seconds": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "code": {
                        "type": "string"
                    },
                    "youtube_id": {
                        "type": "string"
                    },
                    "event_date": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "UserCreate": {
                "type": "object",
                "required": [
                    "name",
                    "email",
                    "role"
                ],
                "additionalProperties": false,
                "properties": {
                    "name": {
                        "type": "string",
                        "minLength": 5,
                        "maxLength": 50
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "description": "Unico, inclusive entre usuarios excluidos. Nao muda depois."
                    },
                    "role": {
                        "type": "string",
                        "enum": [
                            "student",
                            "teacher"
                        ],
                        "description": "Fixo na criacao."
                    },
                    "send_invite": {
                        "type": "boolean",
                        "default": true,
                        "description": "Envia o link de definir senha."
                    },
                    "cpf": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "CPF ou CNPJ, com ou sem pontuacao; gravado so com os digitos. So com special.personal_data. Obrigatorio se a escola exigir."
                    },
                    "address": {
                        "$ref": "#/components/schemas/AddressWrite"
                    }
                }
            },
            "UserUpdate": {
                "type": "object",
                "minProperties": 1,
                "additionalProperties": false,
                "description": "`email`, `role`, `status` e `password` sao recusados com 422.",
                "properties": {
                    "name": {
                        "type": "string",
                        "minLength": 5,
                        "maxLength": 50
                    },
                    "cpf": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "CPF ou CNPJ, com ou sem pontuacao; gravado so com os digitos. null ou vazio remove. So com special.personal_data."
                    },
                    "address": {
                        "$ref": "#/components/schemas/AddressWrite"
                    }
                }
            },
            "AddressWrite": {
                "type": "object",
                "additionalProperties": false,
                "description": "So com `special.personal_data`. Envie so os campos a gravar.",
                "properties": {
                    "zip_code": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 20
                    },
                    "street": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 80
                    },
                    "number": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 10
                    },
                    "complement": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 80
                    },
                    "neighborhood": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 80
                    },
                    "city": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 80
                    },
                    "state": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 80
                    },
                    "phone": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 11,
                        "description": "So digitos, com DDD."
                    }
                }
            },
            "InviteResult": {
                "type": "object",
                "properties": {
                    "sent": {
                        "type": "boolean"
                    },
                    "reason": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "enum": [
                            "not_requested",
                            "mail_failed",
                            "recently_sent",
                            "user_inactive",
                            null
                        ]
                    }
                }
            },
            "GroupWrite": {
                "type": "object",
                "additionalProperties": false,
                "description": "Na criacao, `name` e obrigatorio.",
                "properties": {
                    "name": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 255
                    },
                    "code": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "maxLength": 100
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "published",
                            "draft"
                        ]
                    }
                }
            },
            "MembersAdd": {
                "type": "object",
                "required": [
                    "user_ids"
                ],
                "additionalProperties": false,
                "properties": {
                    "user_ids": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "integer"
                        }
                    }
                }
            },
            "MembersResult": {
                "type": "object",
                "properties": {
                    "added": {
                        "type": "integer",
                        "description": "Entraram agora."
                    },
                    "already_members": {
                        "type": "integer"
                    },
                    "skipped": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "user_id": {
                                    "type": "integer"
                                },
                                "reason": {
                                    "type": "string",
                                    "enum": [
                                        "not_found"
                                    ]
                                }
                            }
                        }
                    }
                }
            },
            "Pagination": {
                "type": "object",
                "description": "Envelope das listas.",
                "required": [
                    "data",
                    "meta"
                ],
                "properties": {
                    "data": {
                        "type": "array",
                        "items": []
                    },
                    "meta": {
                        "type": "object",
                        "required": [
                            "page",
                            "per_page",
                            "total"
                        ],
                        "properties": {
                            "page": {
                                "type": "integer"
                            },
                            "per_page": {
                                "type": "integer"
                            },
                            "total": {
                                "type": "integer"
                            }
                        }
                    },
                    "links": {
                        "type": "object",
                        "properties": {
                            "first": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "last": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "prev": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "next": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        }
                    }
                }
            }
        },
        "responses": {
            "NaoAutenticado": {
                "description": "Token ausente, invalido, expirado, revogado, suspenso ou vindo de um IP\nfora da lista permitida.\n\nA resposta e a **mesma** em todos esses casos, de proposito: distinguir\n\"nao existe\" de \"expirado\" ajudaria quem esta tentando adivinhar. O\nmotivo real fica na auditoria da escola, que o administrador consulta.\n",
                "headers": {
                    "WWW-Authenticate": {
                        "schema": {
                            "type": "string"
                        }
                    },
                    "X-Request-Id": {
                        "$ref": "#/components/headers/XRequestId"
                    }
                },
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "unauthenticated",
                            "title": "Credencial invalida.",
                            "status": 401,
                            "request_id": "550e8400-e29b-41d4-a716-446655440000"
                        }
                    }
                }
            },
            "SemPermissao": {
                "description": "O token e valido, mas nao tem a permissao que o endereco exige. O\n`detail` diz qual permissao falta.\n",
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "forbidden",
                            "title": "Permissao insuficiente.",
                            "status": 403,
                            "detail": "Este endereco exige a permissao 'courses.write', que nao esta neste token.",
                            "request_id": "550e8400-e29b-41d4-a716-446655440000"
                        }
                    }
                }
            },
            "SemTls": {
                "description": "Chamada em HTTP. Nao ha redirecionamento para HTTPS de proposito: um\nredirecionamento faria o token viajar aberto na primeira chamada.\n",
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "tls-required",
                            "title": "Somente HTTPS.",
                            "status": 403
                        }
                    }
                }
            },
            "TokenNoLugarErrado": {
                "description": "O token foi enviado na URL, no corpo ou em cookie. Nesses lugares ele\nfica gravado no registro do servidor e no historico do navegador: use o\ncabecalho `Authorization`.\n",
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "token-in-query-string",
                            "title": "Token fora do lugar.",
                            "status": 400
                        }
                    }
                }
            },
            "NaoEncontrado": {
                "description": "O recurso nao existe, nao pertence a esta escola, ou a API nao esta\nliberada para a escola.\n\nOs casos sao indistinguiveis de proposito: um `403` confirmaria que o\nrecurso existe.\n",
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "not-found",
                            "title": "Recurso nao encontrado.",
                            "status": 404
                        }
                    }
                }
            },
            "DadosInvalidos": {
                "description": "Campo obrigatorio ausente, valor invalido ou campo desconhecido. A API\n**recusa** campo que nao conhece em vez de ignorar, para que um nome\nerrado nao passe por alteracao bem-sucedida.\n",
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "validation-failed",
                            "title": "Dados invalidos.",
                            "status": 422,
                            "errors": {
                                "email": [
                                    "O e-mail e obrigatorio."
                                ]
                            }
                        }
                    }
                }
            },
            "ChaveEmConflito": {
                "description": "A `Idempotency-Key` ja foi usada com um pedido diferente, ou uma chamada\ncom a mesma chave esta em andamento. Gere uma chave nova para cada\noperacao.\n",
                "headers": {
                    "Retry-After": {
                        "$ref": "#/components/headers/RetryAfter"
                    }
                },
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "idempotency-key-conflict",
                            "title": "Idempotency-Key ja usada com outro pedido.",
                            "status": 409
                        }
                    }
                }
            },
            "Conflito": {
                "description": "O pedido esta bem formado, mas uma regra da escola impede a operacao no\nestado atual do recurso. O `reason` diz qual — trate por ele, nao pelo\ntexto.\n",
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "conflict",
                            "title": "O curso tem 3 matricula(s).",
                            "status": 409,
                            "detail": "Curso com matricula nao e excluido pela API. Despublique-o para tira-lo da vitrine.",
                            "reason": "has_enrollments"
                        }
                    }
                }
            },
            "TipoNaoSuportado": {
                "description": "O corpo nao e JSON. Envie `Content-Type application/json`.",
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "unsupported-media-type",
                            "title": "O corpo precisa ser JSON.",
                            "status": 415
                        }
                    }
                }
            },
            "CorpoGrande": {
                "description": "Corpo acima de 1 MB. Para muitos registros, use as chamadas em lote.",
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "payload-too-large",
                            "title": "Corpo da requisicao muito grande.",
                            "status": 413
                        }
                    }
                }
            },
            "LimiteAlcancado": {
                "description": "Limite de requisicoes alcancado. Espere o tempo de `Retry-After`.",
                "headers": {
                    "Retry-After": {
                        "$ref": "#/components/headers/RetryAfter"
                    },
                    "X-RateLimit-Limit": {
                        "$ref": "#/components/headers/XRateLimitLimit"
                    },
                    "X-RateLimit-Remaining": {
                        "$ref": "#/components/headers/XRateLimitRemaining"
                    },
                    "X-RateLimit-Reset": {
                        "$ref": "#/components/headers/XRateLimitReset"
                    }
                },
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "rate-limited",
                            "title": "Limite de requisicoes alcancado.",
                            "status": 429,
                            "detail": "Limite de requisicoes por minuto alcancado."
                        }
                    }
                }
            },
            "Indisponivel": {
                "description": "Escola suspensa, em manutencao, ou servico temporariamente fora do ar.\nTente de novo depois do tempo de `Retry-After`.\n",
                "headers": {
                    "Retry-After": {
                        "$ref": "#/components/headers/RetryAfter"
                    }
                },
                "content": {
                    "application/problem+json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "school-unavailable",
                            "title": "Escola indisponivel.",
                            "status": 503
                        }
                    }
                }
            }
        }
    }
}