Ir para o conteúdo
HotLearn

Documentação da API

Referência

Todos os endereços da API, gerados da especificação OpenAPI 1.0.0-beta. Os exemplos usam o endereço deste servidor.

Baixar openapi.json

Descoberta

Descoberta automática dos endereços de autorização.

GET /.well-known/oauth-authorization-server

Metadados do servidor de autorização

Sem chave de acesso

Documento RFC 8414 com os endereços de autorização, troca e revogação, os escopos aceitos e o método PKCE (S256).

Exemplo

curl https://hotlearn.com.br/.well-known/oauth-authorization-server

Respostas

200 Metadados application/json
{
    "issuer": "https://hotlearn.com.br",
    "authorization_endpoint": "https://hotlearn.com.br/oauth/authorize",
    "token_endpoint": "https://hotlearn.com.br/oauth/token",
    "revocation_endpoint": "https://hotlearn.com.br/oauth/revoke",
    "scopes_supported": [
        "catalog:public",
        "account:read",
        "catalog:read"
    ],
    "response_types_supported": [
        "code"
    ],
    "grant_types_supported": [
        "authorization_code",
        "refresh_token",
        "client_credentials"
    ],
    "code_challenge_methods_supported": [
        "S256"
    ],
    "token_endpoint_auth_methods_supported": [
        "client_secret_post",
        "client_secret_basic",
        "none"
    ],
    "service_documentation": "https://hotlearn.com.br/desenvolvedores"
}
GET /.well-known/oauth-protected-resource

Metadados da API (recurso protegido)

Sem chave de acesso

Documento RFC 9728 da /api/v1, apontando para o servidor de autorização. Também responde em /.well-known/oauth-protected-resource/api/v1. Usado por clientes MCP.

Exemplo

curl https://hotlearn.com.br/.well-known/oauth-protected-resource

Respostas

200 Metadados application/json
{
    "resource": "https://hotlearn.com.br/api/v1",
    "authorization_servers": [
        "https://hotlearn.com.br"
    ],
    "scopes_supported": [
        "catalog:public",
        "account:read",
        "catalog:read"
    ],
    "bearer_methods_supported": [
        "header"
    ],
    "resource_name": "HotLearn API",
    "resource_documentation": "https://hotlearn.com.br/desenvolvedores"
}

Autorização

Autorização OAuth 2.1: pedir acesso, trocar o código pela chave, renovar e revogar.

GET /oauth/authorize

Pedir autorização (abre a tela do HotLearn)

Abrir no navegador da pessoa

Abra este endereço no navegador da pessoa. Ela entra no HotLearn (se ainda não estiver), vê o que o aplicativo poderá fazer e autoriza. Só o dono de uma conta com assinatura ativa ou em teste autoriza. Ao autorizar, o HotLearn volta para o redirect_uri com code e state; ao negar, com error=access_denied. Endereço de retorno fora do cadastro do aplicativo não volta para ele: o HotLearn mostra uma página de erro.

Antes de tudo (inclusive antes de mandar ao cadastro com signup=1), o HotLearn confere o pedido: PKCE S256 (senão, código invalid_request) e external_id (external_id_required, invalid_external_id). Pedido recusado mostra a página de erro com status 400, sem voltar ao aplicativo.

Reconectar: se a conta já tem conexão ativa com o mesmo aplicativo, o mesmo external_id e o mesmo redirect_uri exato (e escopos já aprovados), o HotLearn aprova sem mostrar a tela e só emite uma chave nova: as chaves antigas continuam valendo e display_name/url não mudam. Quando o dono aprova na tela (sempre numa conexão nova, ou quando o aplicativo manda prompt=consent), a conexão é substituída: as chaves antigas param e o nome e o endereço são atualizados.

Parâmetros

NomeTipoDescrição
response_typeobrigatório string = code Sempre code.
client_idobrigatório string Identificador do aplicativo, recebido no cadastro.
redirect_uriobrigatório string Endereço de retorno cadastrado (aceita padrão de subdomínio, ex.: https://*.exemplo.com/retorno). Em produção, só https; http vale apenas fora de produção (testes).
scopeobrigatório string Escopos separados por espaço, ex.: account:read catalog:read.
stateobrigatório string Valor aleatório seu; volta igual no retorno. Confira-o. Com signup=1, a pessoa pode voltar até 2 horas depois com o mesmo state: guarde-o por pelo menos 2 horas (recomendado: 2 h 15 min).
code_challengeobrigatório string PKCE: BASE64URL(SHA256(code_verifier)).
code_challenge_methodobrigatório string = S256 Sempre S256.
external_idopcional string Identificador do cliente do seu lado (ex.: a escola; o id do tenant, um UUID cabe). Cada (conta, aplicativo, external_id) é uma conexão. De 1 a 64 caracteres entre A-Z a-z 0-9 . _ : -; fora disso (inclusive mais de 64), página de erro 400 com o código invalid_external_id — nunca é cortado. Opcional para aplicativo de uma conta só (ex.: assistente de IA); obrigatório para aplicativo cadastrado como de várias escolas (como o EstudioLMS): sem ele, página de erro 400 com o código external_id_required.
display_nameopcional string Opcional. Nome para mostrar ("Em nome de …"). Só é aceito quando o host de url é o mesmo do redirect_uri.
urlopcional string Opcional. Endereço do seu lado (ex.: a escola), do mesmo host do redirect_uri.
promptopcional string Opcional. consent mostra a tela mesmo quando a conexão já existe. Aprovar na tela substitui a conexão: as chaves antigas param e o nome e o endereço são atualizados. Use quando quiser trocar ou atualizar a conexão.
signupopcional integer Opcional. Quem não está logado vai ao cadastro do HotLearn (aviso "Você está assinando por …") e, depois do plano ou do teste grátis, volta uma vez para esta tela. O pedido fica guardado por 2 horas (guarde o state por pelo menos esse tempo). PKCE e external_id são conferidos antes de mandar ao cadastro.

Exemplo de endereço

https://hotlearn.com.br/oauth/authorize?response_type=code&client_id=SEU_CLIENT_ID&redirect_uri=https%3A%2F%2Fescola.exemplo.com%2Fhotlearn%2Fretorno&scope=account%3Aread%20catalog%3Aread&state=ALEATORIO&code_challenge=DESAFIO&code_challenge_method=S256&external_id=42&display_name=Escola%20Exemplo&url=https%3A%2F%2Fescola.exemplo.com

Respostas

302 Volta ao redirect_uri com code e state (ou error=access_denied).
400 Pedido inválido: página de erro do HotLearn, sem redirecionar. Código na página: invalid_request (PKCE ausente ou diferente de S256), external_id_required ou invalid_external_id.
401 Aplicativo desconhecido ou retorno fora do cadastro: página de erro do HotLearn, sem redirecionar.
POST /oauth/token

Trocar o código pela chave, renovar ou pedir chave de aplicativo

Sem chave de acesso

Três usos, pelo grant_type:

  • authorization_code: troca o code (vale 10 minutos, uso único) pela chave de acesso e pela chave de renovação. Mande o code_verifier do PKCE.
  • refresh_token: troca a chave de renovação por um par novo. A antiga deixa de valer; usá-la de novo desfaz a conexão inteira.
  • client_credentials: só aplicativo confidencial; a chave só vale para a vitrine pública (catalog:public).

A chave de acesso vale 1 hora; a de renovação, 30 dias sem uso. Erros seguem o padrão OAuth (error, error_description). Limite: 60 chamadas/min por aplicativo e endereço. Depois que a conexão foi desfeita, a renovação responde no formato do OAuth ({"error": "invalid_grant", …}, status 400), e não em application/problem+json: peça para o dono autorizar de novo.

Exemplo

curl -X POST https://hotlearn.com.br/oauth/token \
  -d grant_type=authorization_code \
  -d client_id=SEU_CLIENT_ID \
  -d client_secret=SEU_SEGREDO \
  -d code=CODIGO_RECEBIDO \
  -d redirect_uri=https://escola.exemplo.com/hotlearn/retorno \
  -d code_verifier=SEU_VERIFIER

Respostas

200 Chaves emitidas application/json
{
    "token_type": "Bearer",
    "expires_in": 3600,
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9…",
    "refresh_token": "def50200a1b2c3…"
}
400 Código ou chave de renovação inválido, vencido ou já usado application/json
{
    "error": "invalid_grant",
    "error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked…"
}
401 Aplicativo ou segredo inválido application/json
{
    "error": "invalid_client",
    "error_description": "Client authentication failed"
}
429 Limite de chamadas estourado (ver Retry-After)
POST /oauth/revoke

Revogar uma chave ou desconectar

Sem chave de acesso

RFC 7009. Com a chave de renovação, desfaz a conexão inteira (é assim que o aplicativo desconecta). Com a chave de acesso, revoga só ela. Responde 200 também para chave desconhecida, como manda a RFC. Aplicativo confidencial manda o segredo. Limite: 30 chamadas por minuto.

Exemplo

curl -X POST https://hotlearn.com.br/oauth/revoke \
  -d token='def50200a1b2c3…' \
  -d client_id=SEU_CLIENT_ID \
  -d client_secret=SEU_SEGREDO

Respostas

200 Revogado (ou chave desconhecida) application/json
[]
400 token ausente application/problem+json
{
    "type": "about:blank",
    "title": "Bad Request",
    "status": 400,
    "detail": "Envie a chave em `token`.",
    "code": "invalid_request"
}
401 Aplicativo ou segredo inválido application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Aplicativo desconhecido.",
    "code": "invalid_client"
}

Conta e conexão

A conta conectada e a própria conexão.

GET /api/v1/me

A conta conectada

Chave com account:read

Conta, quem autorizou, plano, situação da assinatura e saldo de créditos. Bom para conferir a conexão logo depois de autorizar. Em subscription vêm só status (trialing, active ou inactive), on_trial e trial_ends_at: não há past_due, data de renovação nem uso do teste.

Exemplo

curl https://hotlearn.com.br/api/v1/me \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Conta application/json
{
    "data": {
        "account": {
            "id": 12,
            "name": "Escola Exemplo"
        },
        "user": {
            "id": 34,
            "name": "Ana Souza",
            "email": "ana@escola.exemplo.com",
            "role": "owner"
        },
        "plan": {
            "name": "Essencial",
            "slug": "essencial"
        },
        "subscription": {
            "status": "active",
            "on_trial": false,
            "trial_ends_at": null
        },
        "credits": {
            "balance": 40,
            "unlimited": false
        },
        "scopes": [
            "account:read",
            "catalog:read"
        ]
    }
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 Falta o escopo da rota (insufficient_scope) ou a conta está inativa (account_inactive) application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A chave não tem a permissão necessária: account:read.",
    "code": "insufficient_scope",
    "scopes": [
        "account:read"
    ]
}
429 Limite de chamadas estourado (rate_limited); veja Retry-After. Mais de 300 respostas 401 sem chave válida por minuto, do mesmo endereço de rede, também bloqueiam esse endereço com 429. application/problem+json
{
    "type": "about:blank",
    "title": "Too Many Requests",
    "status": 429,
    "detail": "Muitas chamadas. Tente de novo depois do tempo indicado em `Retry-After`.",
    "code": "rate_limited"
}
GET /api/v1/usage

Créditos pelo uso da API

Chave com account:read

A tabela que vale para esta chave: para cada ação medida (export_pdf_section, export_pdf, export_scorm, acquisition, publication, login_link), quantos créditos ela custa, se a cobrança já está ligada (charging), a franquia grátis do mês e o limite por dia, com o que já foi usado. Consulte antes de uma operação pesada para avisar a pessoa. Detalhes no guia Créditos e limites de uso.

Com charging: false, a regra está em simulação: o uso é contado, mas nenhum crédito sai (X-Credits-Charged: 0). O limite por dia vale nos dois casos. O plano Ilimitado não fica isento sozinho: vale o que a tabela diz para ele.

Exemplo

curl https://hotlearn.com.br/api/v1/usage \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Tabela vigente application/json
{
    "data": {
        "balance": 4200,
        "unlimited": false,
        "actions": [
            {
                "action": "export_pdf",
                "credits": 20,
                "charging": true,
                "free_monthly": 20,
                "used_this_month": 20,
                "daily_limit": 50,
                "used_today": 3
            },
            {
                "action": "publication",
                "credits": 0,
                "charging": false,
                "free_monthly": null,
                "used_this_month": 0,
                "daily_limit": null,
                "used_today": 0
            }
        ]
    }
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 Falta o escopo da rota (insufficient_scope) ou a conta está inativa (account_inactive) application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A chave não tem a permissão necessária: account:read.",
    "code": "insufficient_scope",
    "scopes": [
        "account:read"
    ]
}
429 Limite de chamadas estourado (rate_limited); veja Retry-After. Mais de 300 respostas 401 sem chave válida por minuto, do mesmo endereço de rede, também bloqueiam esse endereço com 429. application/problem+json
{
    "type": "about:blank",
    "title": "Too Many Requests",
    "status": 429,
    "detail": "Muitas chamadas. Tente de novo depois do tempo indicado em `Retry-After`.",
    "code": "rate_limited"
}
GET /api/v1/connection

A própria conexão

Qualquer chave de aplicativo

O que o HotLearn sabe da conexão desta chave: aplicativo, external_id, nome e endereço, link "abrir lá" e ações. Chave pessoal não tem conexão (404 no_connection).

Exemplo

curl https://hotlearn.com.br/api/v1/connection \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Conexão application/json
{
    "data": {
        "id": 7,
        "client": {
            "id": "01a13fdf-7c67-70b3-a3b7-bb60430403d8",
            "name": "EstudioLMS"
        },
        "external_id": "42",
        "display_name": "Escola Exemplo",
        "url": "https://escola.exemplo.com",
        "open_url_template": "https://escola.exemplo.com/hotlearn/enviar?produto={product}&material={material}&acao={action}",
        "actions": [
            {
                "key": "course",
                "label": "Criar um curso novo",
                "materials": [
                    "apostila"
                ]
            }
        ],
        "scopes": [
            "account:read",
            "catalog:read",
            "connection:write"
        ],
        "authorized_by": {
            "name": "Ana Souza"
        },
        "authorized_at": "2026-10-15T14:02:11-03:00",
        "last_used_at": "2026-10-16T09:40:00-03:00"
    }
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
404 Chave pessoal (sem conexão) application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Esta chave não pertence a uma conexão de aplicativo (chave pessoal).",
    "code": "no_connection"
}
PUT /api/v1/connection

Ensinar ao HotLearn como abrir o seu lado

Chave com connection:write

Atualiza display_name, url, open_url_template e actions. É daí que sai o botão "Enviar para {display_name}" nos materiais do assinante. O open_url_template precisa ser https (em produção) e do mesmo host de url; use {product}, {material} e {action} onde precisar. Campos ausentes ficam como estão.

Exemplo

curl -X PUT https://hotlearn.com.br/api/v1/connection \
  -H "Authorization: Bearer $HOTLEARN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"display_name":"Escola Exemplo","url":"https://escola.exemplo.com","open_url_template":"https://escola.exemplo.com/hotlearn/enviar?produto={product}&material={material}&acao={action}","actions":[{"key":"course","label":"Criar um curso novo","materials":["apostila"]},{"key":"scorm","label":"Criar uma aula SCORM","materials":["scorm"]}]}'

Respostas

200 Conexão atualizada application/json
{
    "data": {
        "id": 7,
        "client": {
            "id": "01a13fdf-7c67-70b3-a3b7-bb60430403d8",
            "name": "EstudioLMS"
        },
        "external_id": "42",
        "display_name": "Escola Exemplo",
        "url": "https://escola.exemplo.com",
        "open_url_template": "https://escola.exemplo.com/hotlearn/enviar?produto={product}&material={material}&acao={action}",
        "actions": [
            {
                "key": "course",
                "label": "Criar um curso novo",
                "materials": [
                    "apostila"
                ]
            }
        ],
        "scopes": [
            "account:read",
            "catalog:read",
            "connection:write"
        ],
        "authorized_by": {
            "name": "Ana Souza"
        },
        "authorized_at": "2026-10-15T14:02:11-03:00",
        "last_used_at": "2026-10-16T09:40:00-03:00"
    }
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 Falta o escopo da rota (insufficient_scope) ou a conta está inativa (account_inactive) application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A chave não tem a permissão necessária: account:read.",
    "code": "insufficient_scope",
    "scopes": [
        "account:read"
    ]
}
404 Chave pessoal (sem conexão)
422 Dados inválidos (validation_failed) application/problem+json
{
    "type": "about:blank",
    "title": "Unprocessable Content",
    "status": 422,
    "detail": "Dados inválidos.",
    "code": "validation_failed",
    "errors": {
        "open_url_template": [
            "Precisa ser do mesmo domínio de `url`."
        ]
    }
}

Acervo

Acervo: produtos, sumário, prévia, capa, categorias e licença.

GET /api/v1/products

Listar produtos

Chave com catalog:readcatalog:public

Acervo (padrão, no idioma pedido), biblioteca da conta (collection=acquired) ou criações da conta (collection=created). Em páginas, por cursor.

  • owned: a conta já adquiriu (ou é criação dela).
  • exportable: há matriz de conteúdo (a cópia personalizada, o original do acervo ou a da criação), que sempre exporta (PDF), ou um curso SCORM da conta sem erro. Quando falso, export_block traz {code, message}: no_matrix (nenhum material) ou scorm_invalid (só cursos SCORM, todos com erro na verificação). Exportável: export_block: null.
  • O filtro exportable=true é feito no banco e não roda a verificação do SCORM: um produto só com cursos SCORM com erro aparece nele, mas vem com exportable: false e scorm_invalid.

Com a chave de aplicativo sem conta (catalog:public), só o acervo e só os campos públicos (sem owned, exportable, credit_cost, público e objetivo).

Parâmetros

NomeTipoDescrição
collectionopcional string catalog (padrão), acquired ou created.
qopcional string Busca no título, na descrição curta, no público e no objetivo (não busca no sumário).
categoryopcional string Categoria: id ou slug.
levelopcional string iniciante, intermediario ou avancado.
exportableopcional boolean true ou false. Feito no banco, sem a verificação do SCORM: confira o exportable de cada item.
localeopcional string Idioma do acervo (pt_BR, en, es); também pelo Accept-Language.
limitopcional integer De 1 a 50 (padrão 12).
cursoropcional string O next_cursor da página anterior.

Exemplo

curl "https://hotlearn.com.br/api/v1/products?collection=catalog&limit=12" \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Página de produtos application/json
{
    "data": [
        {
            "id": 136,
            "slug": "arte-e-cultura",
            "title": "Arte e Cultura",
            "short_description": "Apostila para turmas do ensino médio.",
            "locale": "pt_BR",
            "category": {
                "id": 5,
                "slug": "educacao-e-ead",
                "name": "Educação e EAD"
            },
            "level": "iniciante",
            "level_label": "Iniciante",
            "workload": "30h",
            "contents": [
                "apostila",
                "quiz_lms"
            ],
            "cover_url": "https://hotlearn.com.br/storage/negocio-pronto/products/136/capa.jpg",
            "published_at": "2026-10-08T14:38:56+00:00",
            "origin": "catalog",
            "audience": "Professores do ensino médio",
            "objective": "Trabalhar arte e cultura com projetos.",
            "credit_cost": 1000,
            "version": "1.0",
            "owned": true,
            "exportable": true,
            "export_block": null,
            "publications_count": 1
        },
        {
            "id": 141,
            "slug": "oficina-de-teatro",
            "title": "Oficina de Teatro",
            "short_description": "Curso SCORM para turmas do ensino médio.",
            "locale": "pt_BR",
            "category": {
                "id": 5,
                "slug": "educacao-e-ead",
                "name": "Educação e EAD"
            },
            "level": "iniciante",
            "level_label": "Iniciante",
            "workload": "30h",
            "contents": [],
            "cover_url": "https://hotlearn.com.br/storage/negocio-pronto/products/141/capa.jpg",
            "published_at": null,
            "origin": "created",
            "audience": "Professores do ensino médio",
            "objective": "Trabalhar arte e cultura com projetos.",
            "credit_cost": 0,
            "version": "1.0",
            "owned": true,
            "exportable": false,
            "export_block": {
                "code": "scorm_invalid",
                "message": "Os cursos SCORM deste produto têm erros e ainda não podem ser exportados. Corrija-os no HotLearn."
            },
            "publications_count": 0
        }
    ],
    "next_cursor": "eyJpZCI6MTM2LCJfcG9pbnRzVG9OZXh0SXRlbXMiOnRydWV9"
}
400 O cursor informado é inválido. Recomece a lista sem ele. application/problem+json
{
    "type": "about:blank",
    "title": "Bad Request",
    "status": 400,
    "detail": "O `cursor` informado é inválido. Recomece a lista sem ele.",
    "code": "invalid_cursor"
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 Falta o escopo da rota (insufficient_scope) ou a conta está inativa (account_inactive) application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A chave não tem a permissão necessária: account:read.",
    "code": "insufficient_scope",
    "scopes": [
        "account:read"
    ]
}
422 Dados inválidos. application/problem+json
{
    "type": "about:blank",
    "title": "Unprocessable Content",
    "status": 422,
    "detail": "Dados inválidos.",
    "code": "validation_failed",
    "errors": {
        "collection": [
            "Use catalog, acquired ou created."
        ]
    }
}
429 Limite de chamadas estourado (rate_limited); veja Retry-After. Mais de 300 respostas 401 sem chave válida por minuto, do mesmo endereço de rede, também bloqueiam esse endereço com 429. application/problem+json
{
    "type": "about:blank",
    "title": "Too Many Requests",
    "status": 429,
    "detail": "Muitas chamadas. Tente de novo depois do tempo indicado em `Retry-After`.",
    "code": "rate_limited"
}
GET /api/v1/products/{product}

Detalhe do produto, com o sumário

Chave com catalog:read

Tudo da lista mais o sumário (toc), a licença e os links de prévia e capa.

toc são as seções da matriz, cortadas nos títulos principais: kind é module, intro (abertura curta) ou appendix (glossário, referências, gabarito…). source diz de onde veio: personalizada (a cópia que a conta editou), original (a do acervo) ou criacao. Ler pela API nunca cria a cópia personalizada.

Produto de outra conta, ou fora do ar e não adquirido: 404.

exportable e export_block seguem a mesma regra da lista: export_block é null quando exporta; senão, {code, message} com no_matrix ou scorm_invalid.

Parâmetros

NomeTipoDescrição
productobrigatório integer Identificador do produto.

Exemplo

curl https://hotlearn.com.br/api/v1/products/136 \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Produto application/json
{
    "data": {
        "id": 136,
        "slug": "arte-e-cultura",
        "title": "Arte e Cultura",
        "short_description": "Apostila para turmas do ensino médio.",
        "locale": "pt_BR",
        "category": {
            "id": 5,
            "slug": "educacao-e-ead",
            "name": "Educação e EAD"
        },
        "level": "iniciante",
        "level_label": "Iniciante",
        "workload": "30h",
        "contents": [
            "apostila",
            "quiz_lms"
        ],
        "cover_url": "https://hotlearn.com.br/storage/negocio-pronto/products/136/capa.jpg",
        "published_at": "2026-10-08T14:38:56+00:00",
        "origin": "catalog",
        "audience": "Professores do ensino médio",
        "objective": "Trabalhar arte e cultura com projetos.",
        "credit_cost": 1000,
        "version": "1.0",
        "owned": true,
        "exportable": true,
        "export_block": null,
        "source": "personalizada",
        "toc": [
            {
                "index": 0,
                "title": "Como aproveitar esta apostila",
                "kind": "intro",
                "words": 310,
                "est_bytes": 4200
            },
            {
                "index": 1,
                "title": "Capítulo 1 — Arte para quê?",
                "kind": "module",
                "words": 1194,
                "est_bytes": 14706
            },
            {
                "index": 2,
                "title": "Glossário",
                "kind": "appendix",
                "words": 420,
                "est_bytes": 5120
            }
        ],
        "license": {
            "id": 1,
            "title": "Licença Comercial",
            "version": "2.0"
        },
        "has_preview": true,
        "links": {
            "preview": "https://hotlearn.com.br/api/v1/products/136/preview",
            "cover": "https://hotlearn.com.br/api/v1/products/136/cover",
            "license": "https://hotlearn.com.br/api/v1/licenses/1"
        }
    }
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 Falta o escopo da rota (insufficient_scope) ou a conta está inativa (account_inactive) application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A chave não tem a permissão necessária: account:read.",
    "code": "insufficient_scope",
    "scopes": [
        "account:read"
    ]
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
GET /api/v1/products/{product}/preview

Prévia em PDF

Chave com catalog:read

O PDF de amostra do produto, entregue direto (application/pdf). 404 quando o produto não tem prévia. Exige chave de conta com catalog:read: a vitrine pública (catalog:public, sem conta) tem só a lista, a capa e as categorias, sem prévia.

Parâmetros

NomeTipoDescrição
productobrigatório integer Identificador do produto.

Exemplo

curl https://hotlearn.com.br/api/v1/products/136/preview \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 O arquivo PDF application/pdf
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
GET /api/v1/products/{product}/cover

Capa

Chave com catalog:readcatalog:public

A imagem da capa, entregue direto. Para mostrar numa página, o cover_url da lista já é um endereço público, sem chave.

Parâmetros

NomeTipoDescrição
productobrigatório integer Identificador do produto.

Exemplo

curl https://hotlearn.com.br/api/v1/products/136/cover \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 A imagem image/*
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
GET /api/v1/categories

Categorias

Chave com catalog:readcatalog:public

Todas as categorias, com quantos produtos do acervo publicado cada uma tem no idioma pedido. Lista curta: vem inteira, sem cursor.

Exemplo

curl https://hotlearn.com.br/api/v1/categories \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Categorias application/json
{
    "data": [
        {
            "id": 5,
            "slug": "educacao-e-ead",
            "name": "Educação e EAD",
            "products_count": 12
        }
    ]
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
GET /api/v1/licenses/{license}

Licença comercial

Chave com catalog:read

Título, versão e texto (HTML) da licença, para mostrar antes de adquirir. O id vem em license no detalhe do produto.

Parâmetros

NomeTipoDescrição
licenseobrigatório integer Identificador da licença.

Exemplo

curl https://hotlearn.com.br/api/v1/licenses/1 \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Licença application/json
{
    "data": {
        "id": 1,
        "title": "Licença Comercial",
        "version": "2.0",
        "active": true,
        "body_html": "<h3>Licença Comercial</h3><p>…</p>"
    }
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}

Aquisições

Adquirir produtos com os créditos da conta e ver o histórico.

POST /api/v1/acquisitions

Adquirir um produto

Chave com acquisitions:write

Desbloqueia o produto para a conta, com a mesma regra do botão do HotLearn: debita os créditos (o custo está em credit_cost), respeita o limite do período de teste, e plano ilimitado não debita.

  • Idempotency-Key obrigatório. Repetir a chamada com a mesma chave devolve a mesma resposta, sem cobrar de novo.
  • Produto já adquirido: 200 com charged: false, sem cobrar.
  • license_version: a versão da licença mostrada à pessoa (GET /licenses/{id}). Se mudou, 409 license_outdated com a versão vigente.
  • on_behalf_of: quem clicou do lado do aplicativo (fica na auditoria do HotLearn).
  • Quem assina do lado do HotLearn é quem autorizou a conexão (ou, se essa pessoa saiu da conta, o dono). Sem nenhum dos dois: 409 connection_owner_missing. Pode consumir créditos da conta conforme a tabela de uso (GET /usage): a resposta cobrada traz X-Credits-Charged e X-Credits-Balance; sem saldo, 402 insufficient_credits; acima do limite do dia, 429 daily_limit_reached.

Parâmetros

NomeTipoDescrição
Idempotency-Keyobrigatório string Obrigatório: um valor único por operação (ex.: um UUID). Sem ele, 400 idempotency_key_required. A resposta (inclusive 4xx) fica guardada por 24 horas e volta igual para a mesma chave; mesma chave com outros dados, 422 idempotency_key_reused; chamada simultânea com a mesma chave, 409 idempotency_in_progress. Use uma chave nova a cada nova tentativa (por exemplo, depois de corrigir o pedido).

Exemplo

curl -X POST https://hotlearn.com.br/api/v1/acquisitions \
  -H "Authorization: Bearer $HOTLEARN_KEY" \
  -H "Idempotency-Key: 6f1c2e8a-3b0d-4c55-9a7e-2f1d9b8c4a10" \
  -H "Content-Type: application/json" \
  -d '{"product_id":136,"license_version":"2.0","on_behalf_of":{"external_user_id":"u-9","name":"Coordenação da Escola","email":"coordenacao@escola.exemplo.com"}}'

Respostas

201 Adquirido agora application/json
{
    "data": {
        "acquisition": {
            "id": 58,
            "product": {
                "id": 136,
                "slug": "arte-e-cultura",
                "title": "Arte e Cultura"
            },
            "acquired_at": "2026-10-16T10:12:00-03:00",
            "source": "plan_credit",
            "credits_spent": 2,
            "license_version": "2.0",
            "acquired_by": {
                "name": "Ana Souza"
            },
            "via": {
                "app": "EstudioLMS",
                "client_id": "01a13fdf-7c67-70b3-a3b7-bb60430403d8",
                "on_behalf_of": {
                    "external_user_id": "u-9",
                    "name": "Coordenação da Escola",
                    "email": "coordenacao@escola.exemplo.com"
                }
            }
        },
        "charged": true,
        "balance": {
            "credits": 38,
            "unlimited": false
        }
    }
}
200 Já era da conta (charged: false, nada cobrado)
400 Envie o cabeçalho Idempotency-Key (um valor único por operação). application/problem+json
{
    "type": "about:blank",
    "title": "Bad Request",
    "status": 400,
    "detail": "Envie o cabeçalho `Idempotency-Key` (um valor único por operação).",
    "code": "idempotency_key_required"
}
402 A conta não tem créditos suficientes para este produto. application/problem+json
{
    "type": "about:blank",
    "title": "Payment Required",
    "status": 402,
    "detail": "A conta não tem créditos suficientes para este produto.",
    "code": "insufficient_credits",
    "required": 5,
    "available": 1
}
403 A assinatura da conta não está ativa. Para adquirir, a conta precisa de assinatura ativa ou do período de teste. application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A assinatura da conta não está ativa. Para adquirir, a conta precisa de assinatura ativa ou do período de teste.",
    "code": "subscription_inactive"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
409 A licença mudou: a versão vigente é 2.0. Mostre a licença nova à pessoa e envie essa versão. application/problem+json
{
    "type": "about:blank",
    "title": "Conflict",
    "status": 409,
    "detail": "A licença mudou: a versão vigente é 2.0. Mostre a licença nova à pessoa e envie essa versão.",
    "code": "license_outdated",
    "license": {
        "id": 1,
        "version": "2.0"
    }
}
422 Dados inválidos (validation_failed) application/problem+json
{
    "type": "about:blank",
    "title": "Unprocessable Content",
    "status": 422,
    "detail": "Dados inválidos.",
    "code": "validation_failed",
    "errors": {
        "open_url_template": [
            "Precisa ser do mesmo domínio de `url`."
        ]
    }
}
GET /api/v1/acquisitions

Histórico de aquisições

Chave com acquisitions:read

Tudo o que a conta adquiriu, do mais recente para o mais antigo, pelo HotLearn ou por qualquer aplicativo: produto, data, origem (plan_credit, trial, unlimited, admin), créditos gastos, versão da licença e, quando veio de um aplicativo, qual (via). Filtro opcional product_id. Em páginas, por cursor.

Parâmetros

NomeTipoDescrição
product_idopcional integer Só as aquisições deste produto.
limitopcional integer De 1 a 50 (padrão 12).
cursoropcional string O next_cursor da página anterior.

Exemplo

curl "https://hotlearn.com.br/api/v1/acquisitions?limit=12" \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Página de aquisições application/json
{
    "data": [
        {
            "id": 58,
            "product": {
                "id": 136,
                "slug": "arte-e-cultura",
                "title": "Arte e Cultura"
            },
            "acquired_at": "2026-10-16T10:12:00-03:00",
            "source": "plan_credit",
            "credits_spent": 2,
            "license_version": "2.0",
            "acquired_by": {
                "name": "Ana Souza"
            },
            "via": {
                "app": "EstudioLMS",
                "client_id": "01a13fdf-7c67-70b3-a3b7-bb60430403d8",
                "on_behalf_of": {
                    "external_user_id": "u-9",
                    "name": "Coordenação da Escola",
                    "email": "coordenacao@escola.exemplo.com"
                }
            }
        }
    ],
    "next_cursor": null
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 Falta o escopo da rota (insufficient_scope) ou a conta está inativa (account_inactive) application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A chave não tem a permissão necessária: account:read.",
    "code": "insufficient_scope",
    "scopes": [
        "account:read"
    ]
}

Materiais e arquivos

Materiais de um produto (matriz, curso SCORM, quadro) e pedidos de arquivo.

GET /api/v1/products/{product}/materials

Materiais do produto

Chave com materials:read

O que a conta tem deste produto:

  • a matriz: a cópia que a conta personalizou (source: personalizada) ou, sem cópia, a original do acervo (original). Ler nunca cria a cópia;
  • o que a conta criou sobre o produto: outras matrizes, cursos SCORM, quadros (criacao).

formats lista os arquivos que já dá para pedir. Curso SCORM traz valid e errors (com erro, o pacote não sai). Exige o produto adquirido (ou criação da conta) e assinatura ativa ou em teste.

Quando a escola personaliza um produto do acervo, a matriz vira uma cópia com outro id (source passa de original a personalizada). Liste os materiais de novo em vez de guardar o id; as publicações antigas avisam com outdated_reason: "personalized" e current_material_id.

Parâmetros

NomeTipoDescrição
productobrigatório integer Identificador do produto.

Exemplo

curl https://hotlearn.com.br/api/v1/products/136/materials \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Materiais application/json
{
    "data": [
        {
            "id": 161,
            "product_id": 136,
            "type": "apostila",
            "title": "Arte e Cultura",
            "source": "personalizada",
            "version": "1790850188",
            "updated_at": "2026-10-08T14:03:08+00:00",
            "formats": [
                "pdf"
            ],
            "exportable": true,
            "sections_count": 26
        },
        {
            "id": 162,
            "product_id": 136,
            "type": "scorm",
            "title": "Curso de Arte",
            "source": "criacao",
            "version": "1791390405",
            "updated_at": "2026-10-14T20:06:45+00:00",
            "formats": [
                "scorm12",
                "scorm2004",
                "html5"
            ],
            "exportable": true,
            "valid": true,
            "errors": []
        }
    ]
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 A conta ainda não adquiriu este produto. Adquira para ler os materiais. application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A conta ainda não adquiriu este produto. Adquira para ler os materiais.",
    "code": "not_acquired"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
GET /api/v1/materials/{material}

Um material

Chave com materials:read

Dados do material, com as seções (capítulos) da matriz ou os avisos do curso SCORM. A resposta traz ETag com a versão: mande If-None-Match com ela e, se nada mudou, a resposta é 304, sem corpo. A versão muda a cada salvamento.

Parâmetros

NomeTipoDescrição
materialobrigatório integer Identificador do material.

Exemplo

curl https://hotlearn.com.br/api/v1/materials/162 \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Material application/json
{
    "data": {
        "id": 161,
        "product_id": 136,
        "type": "apostila",
        "title": "Arte e Cultura",
        "source": "personalizada",
        "version": "1790850188",
        "updated_at": "2026-10-08T14:03:08+00:00",
        "formats": [
            "pdf"
        ],
        "exportable": true,
        "sections_count": 26,
        "sections": [
            {
                "index": 0,
                "title": "Capítulo 1 — Arte para quê?",
                "kind": "module",
                "words": 1194,
                "est_bytes": 14706
            }
        ]
    }
}
304 Não mudou desde a versão do If-None-Match
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 A conta ainda não adquiriu este produto. Adquira para ler os materiais. application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A conta ainda não adquiriu este produto. Adquira para ler os materiais.",
    "code": "not_acquired"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
GET /api/v1/materials/{material}/content

Conteúdo da matriz

Chave com materials:read

A matriz inteira, no format pedido:

  • html: HTML de lição, para colar num editor de LMS. Só estrutura simples (títulos, parágrafos, listas, tabelas, citações, imagens) e cor em estilo dentro das próprias tags: caixas viram tabela de uma célula com fundo, que os editores (como o CKEditor 4) mantêm ao editar. Sem classes, sem <style>, sem script. As respostas das perguntas vão num bloco Gabarito no fim.
  • markdown: para IA, MCP e ferramentas de texto. Caixas viram citação; checklist vira - [ ]; gabarito no fim.
  • json: o documento do editor (o mesmo do "Exportar JSON" do HotLearn).

Rótulos ("Gabarito", "Questão", "Atividade") saem no idioma do material. ETag e If-None-Match como em GET /materials/{id}.

Parâmetros

NomeTipoDescrição
materialobrigatório integer Identificador da matriz.
formatopcional string html (padrão), markdown ou json.

Exemplo

curl "https://hotlearn.com.br/api/v1/materials/161/content?format=html" \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Conteúdo application/json
{
    "data": {
        "material_id": 161,
        "version": "1790850188",
        "source": "personalizada",
        "format": "html",
        "title": "Inglês para Viagem",
        "content": "<h2>O cartão de embarque</h2><p>Boarding é quando o embarque começa…</p><table cellpadding=\"0\" cellspacing=\"0\" style=\"width:100%;border-collapse:collapse;margin:16px 0\"><tr><td style=\"background:#e8f3f5;border-left:4px solid #1d8a9c;padding:12px 16px\"><p><strong>Dica</strong></p><p>Confira o painel.</p></td></tr></table>…<h2>Gabarito</h2><ol style=\"list-style:none;padding-left:0\"><li>Questão 1. D) Até 22:35</li></ol>"
    }
}
304 Não mudou
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 A conta ainda não adquiriu este produto. Adquira para ler os materiais. application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A conta ainda não adquiriu este produto. Adquira para ler os materiais.",
    "code": "not_acquired"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
422 Formato não disponível para este material. Use: html, markdown, json. application/problem+json
{
    "type": "about:blank",
    "title": "Unprocessable Content",
    "status": 422,
    "detail": "Formato não disponível para este material. Use: html, markdown, json.",
    "code": "format_unavailable",
    "formats": [
        "html",
        "markdown",
        "json"
    ]
}
GET /api/v1/materials/{material}/sections/{section}

Um capítulo da matriz

Chave com materials:read

Uma seção do sumário (index de GET /materials/{id}), em html ou markdown. O título do capítulo vem em title, fora do corpo: no LMS, ele vira o nome da lição. O gabarito das perguntas do capítulo vai no fim do corpo.

Parâmetros

NomeTipoDescrição
materialobrigatório integer Identificador da matriz.
sectionobrigatório integer index da seção.
formatopcional string html (padrão) ou markdown.

Exemplo

curl "https://hotlearn.com.br/api/v1/materials/161/sections/1?format=html" \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Capítulo application/json
{
    "data": {
        "material_id": 161,
        "version": "1790850188",
        "source": "personalizada",
        "format": "html",
        "title": "Módulo 2 — No aeroporto e a bordo",
        "section": {
            "index": 1,
            "title": "Módulo 2 — No aeroporto e a bordo",
            "kind": "module",
            "words": 2210,
            "est_bytes": 26003
        },
        "content": "<h2>O cartão de embarque</h2><p>Boarding é quando o embarque começa…</p><table cellpadding=\"0\" cellspacing=\"0\" style=\"width:100%;border-collapse:collapse;margin:16px 0\"><tr><td style=\"background:#e8f3f5;border-left:4px solid #1d8a9c;padding:12px 16px\"><p><strong>Dica</strong></p><p>Confira o painel.</p></td></tr></table>…<h2>Gabarito</h2><ol style=\"list-style:none;padding-left:0\"><li>Questão 1. D) Até 22:35</li></ol>"
    }
}
304 Não mudou
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 A conta ainda não adquiriu este produto. Adquira para ler os materiais. application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A conta ainda não adquiriu este produto. Adquira para ler os materiais.",
    "code": "not_acquired"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
422 Formato não disponível para este material. Use: html, markdown, json. application/problem+json
{
    "type": "about:blank",
    "title": "Unprocessable Content",
    "status": 422,
    "detail": "Formato não disponível para este material. Use: html, markdown, json.",
    "code": "format_unavailable",
    "formats": [
        "html",
        "markdown",
        "json"
    ]
}
POST /api/v1/materials/{material}/exports

Pedir um arquivo

Chave com materials:read

Pede o arquivo de um material num dos formats dele:

  • matriz: pdf — inteira, ou só um capítulo com section (o index do sumário; o PDF do capítulo sai sem capa, sumário e contracapa);

  • curso SCORM: scorm12, scorm2004 ou html5.

  • Já há um arquivo pronto da mesma versão, formato e capítulo: 200 com o pedido ready.

  • Senão: 202 com o pedido queued. Acompanhe em GET /exports/{id} até ready e baixe em /file.

  • Curso SCORM com erro: 422 scorm_invalid com a lista em errors (corrigir no editor SCORM do HotLearn).

  • Idempotency-Key obrigatório. Pode consumir créditos da conta conforme a tabela de uso (GET /usage): a resposta cobrada traz X-Credits-Charged e X-Credits-Balance; sem saldo, 402 insufficient_credits; acima do limite do dia, 429 daily_limit_reached.

Parâmetros

NomeTipoDescrição
materialobrigatório integer Identificador do material.
Idempotency-Keyobrigatório string Obrigatório: um valor único por operação (ex.: um UUID). Sem ele, 400 idempotency_key_required. A resposta (inclusive 4xx) fica guardada por 24 horas e volta igual para a mesma chave; mesma chave com outros dados, 422 idempotency_key_reused; chamada simultânea com a mesma chave, 409 idempotency_in_progress. Use uma chave nova a cada nova tentativa (por exemplo, depois de corrigir o pedido).

Exemplo

curl -X POST https://hotlearn.com.br/api/v1/materials/162/exports \
  -H "Authorization: Bearer $HOTLEARN_KEY" \
  -H "Idempotency-Key: 6f1c2e8a-3b0d-4c55-9a7e-2f1d9b8c4a10" \
  -H "Content-Type: application/json" \
  -d '{"format":"scorm12"}'

Respostas

202 Pedido criado (queued) application/json
{
    "data": {
        "id": 31,
        "material_id": 162,
        "format": "scorm12",
        "section": null,
        "version": "1791390405",
        "status": "queued",
        "size": null,
        "expires_at": null,
        "error": null,
        "links": {
            "self": "https://hotlearn.com.br/api/v1/exports/31",
            "file": null
        }
    }
}
200 Já estava pronto (ready) application/json
{
    "data": {
        "id": 31,
        "material_id": 162,
        "format": "scorm12",
        "section": null,
        "version": "1791390405",
        "status": "ready",
        "size": 98155,
        "expires_at": "2026-10-17T19:42:58+00:00",
        "error": null,
        "links": {
            "self": "https://hotlearn.com.br/api/v1/exports/31",
            "file": "https://hotlearn.com.br/api/v1/exports/31/file"
        }
    }
}
400 Envie o cabeçalho Idempotency-Key (um valor único por operação). application/problem+json
{
    "type": "about:blank",
    "title": "Bad Request",
    "status": 400,
    "detail": "Envie o cabeçalho `Idempotency-Key` (um valor único por operação).",
    "code": "idempotency_key_required"
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 A conta ainda não adquiriu este produto. Adquira para ler os materiais. application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A conta ainda não adquiriu este produto. Adquira para ler os materiais.",
    "code": "not_acquired"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
422 O curso SCORM tem erros e não pode ser gerado. Corrija no editor SCORM do HotLearn. application/problem+json
{
    "type": "about:blank",
    "title": "Unprocessable Content",
    "status": 422,
    "detail": "O curso SCORM tem erros e não pode ser gerado. Corrija no editor SCORM do HotLearn.",
    "code": "scorm_invalid",
    "errors": [
        {
            "code": "no_screens",
            "message": "O curso não tem telas."
        }
    ]
}
GET /api/v1/exports/{export}

Andamento do pedido

Chave com materials:read

status: queued (na fila), running (gerando), ready (pronto, com size e expires_at), failed (com error) ou expired (passou das 24 horas; peça de novo). Consulte a cada poucos segundos até sair de queued/running.

Parâmetros

NomeTipoDescrição
exportobrigatório integer Identificador do pedido.

Exemplo

curl https://hotlearn.com.br/api/v1/exports/31 \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Pedido application/json
{
    "data": {
        "id": 31,
        "material_id": 162,
        "format": "scorm12",
        "section": null,
        "version": "1791390405",
        "status": "ready",
        "size": 98155,
        "expires_at": "2026-10-17T19:42:58+00:00",
        "error": null,
        "links": {
            "self": "https://hotlearn.com.br/api/v1/exports/31",
            "file": "https://hotlearn.com.br/api/v1/exports/31/file"
        }
    }
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
GET /api/v1/exports/{export}/file

Baixar o arquivo

Chave com materials:read

O arquivo pronto (application/pdf ou application/zip). Fica disponível por 24 horas. Ainda não pronto (ou falhou): 409 export_not_ready. Vencido: 410 export_expired.

Parâmetros

NomeTipoDescrição
exportobrigatório integer Identificador do pedido.

Exemplo

curl https://hotlearn.com.br/api/v1/exports/31/file \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 O arquivo application/pdf
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
409 O arquivo ainda não está pronto. Consulte o pedido e tente de novo em instantes. application/problem+json
{
    "type": "about:blank",
    "title": "Conflict",
    "status": "running",
    "detail": "O arquivo ainda não está pronto. Consulte o pedido e tente de novo em instantes.",
    "code": "export_not_ready"
}
410 O arquivo venceu (fica 24 horas). Faça um pedido novo. application/problem+json
{
    "type": "about:blank",
    "title": "Gone",
    "status": 410,
    "detail": "O arquivo venceu (fica 24 horas). Faça um pedido novo.",
    "code": "export_expired"
}
GET /api/v1/products/{product}/quizzes

Provas do produto

Chave com materials:read

A prova do produto, com o número de questões e os formats disponíveis: o CSV de cada plataforma que o produto traz (csv-lms-estudio, csv-moodle, csv) e sempre json. Mesmas regras de posse dos materiais.

Parâmetros

NomeTipoDescrição
productobrigatório integer Identificador do produto.

Exemplo

curl https://hotlearn.com.br/api/v1/products/136/quizzes \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Provas application/json
{
    "data": [
        {
            "id": 412,
            "product_id": 136,
            "title": "Prova — CSV (LMS Estúdio)",
            "questions_count": 10,
            "formats": [
                "csv-lms-estudio",
                "csv-moodle",
                "json"
            ]
        }
    ]
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 A conta ainda não adquiriu este produto. Adquira para ler os materiais. application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A conta ainda não adquiriu este produto. Adquira para ler os materiais.",
    "code": "not_acquired"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
GET /api/v1/quizzes/{quiz}

Uma prova num formato

Chave com materials:read

  • csv-lms-estudio, csv-moodle, csv: o arquivo original (text/csv), para importar com o importador da própria plataforma.
  • json (padrão): as perguntas lidas do CSV, com as alternativas e qual é a certa.

Parâmetros

NomeTipoDescrição
quizobrigatório integer id da prova (de GET /products/{id}/quizzes).
formatopcional string json (padrão) ou um dos CSV.

Exemplo

curl "https://hotlearn.com.br/api/v1/quizzes/412?format=json" \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 A prova application/json
{
    "data": {
        "id": 412,
        "product_id": 136,
        "title": "Prova — CSV (LMS Estúdio)",
        "questions_count": 10,
        "formats": [
            "csv-lms-estudio",
            "csv-moodle",
            "json"
        ],
        "questions": [
            {
                "text": "Qual o portão do voo?",
                "points": 10,
                "options": [
                    {
                        "text": "B12",
                        "correct": false
                    },
                    {
                        "text": "B15",
                        "correct": true
                    }
                ]
            }
        ]
    }
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 A conta ainda não adquiriu este produto. Adquira para ler os materiais. application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A conta ainda não adquiriu este produto. Adquira para ler os materiais.",
    "code": "not_acquired"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
422 Formato não disponível para este material. Use: csv-lms-estudio, csv-moodle, json. application/problem+json
{
    "type": "about:blank",
    "title": "Unprocessable Content",
    "status": 422,
    "detail": "Formato não disponível para este material. Use: csv-lms-estudio, csv-moodle, json.",
    "code": "format_unavailable",
    "formats": [
        "csv-lms-estudio",
        "csv-moodle",
        "json"
    ]
}

Publicações

O que o aplicativo criou do lado dele a partir dos materiais.

POST /api/v1/publications

Registrar uma publicação

Chave com publications:write

Conta ao HotLearn o que o aplicativo criou do lado dele a partir de um material: um curso, uma lição, uma aula SCORM. A publicação aparece para a escola na página Integrações do HotLearn.

  • Informe material_id (ou só product_id) e kind (course, lesson, scorm_lesson, other).
  • material_version é a versão usada (padrão: a atual). Quando a escola salvar o material de novo (ou personalizar o original do acervo), a publicação volta com outdated: true e o motivo em outdated_reason (updated ou personalized): é a deixa para oferecer a atualização.
  • parts: os capítulos enviados (index do sumário), cada um com a referência do seu lado.
  • external_ref e external_url: como achar o item do seu lado.
  • Só aplicativo autorizado (com conexão). Idempotency-Key obrigatório. Pode consumir créditos da conta conforme a tabela de uso (GET /usage): a resposta cobrada traz X-Credits-Charged e X-Credits-Balance; sem saldo, 402 insufficient_credits; acima do limite do dia, 429 daily_limit_reached.

Parâmetros

NomeTipoDescrição
Idempotency-Keyobrigatório string Obrigatório: um valor único por operação (ex.: um UUID). Sem ele, 400 idempotency_key_required. A resposta (inclusive 4xx) fica guardada por 24 horas e volta igual para a mesma chave; mesma chave com outros dados, 422 idempotency_key_reused; chamada simultânea com a mesma chave, 409 idempotency_in_progress. Use uma chave nova a cada nova tentativa (por exemplo, depois de corrigir o pedido).

Exemplo

curl -X POST https://hotlearn.com.br/api/v1/publications \
  -H "Authorization: Bearer $HOTLEARN_KEY" \
  -H "Idempotency-Key: 6f1c2e8a-3b0d-4c55-9a7e-2f1d9b8c4a10" \
  -H "Content-Type: application/json" \
  -d '{"material_id":161,"kind":"course","title":"Inglês para Viagem — Turma A","external_ref":"curso-77","external_url":"https://escola.lmsestudio.com/cursos/77","parts":[{"index":1,"title":"Módulo 2 — No aeroporto","external_ref":"licao-301"}],"on_behalf_of":{"external_user_id":"u-9","name":"Coordenação da Escola"}}'

Respostas

201 Registrada application/json
{
    "data": {
        "id": 15,
        "product": {
            "id": 136,
            "title": "Inglês para Viagem"
        },
        "material_id": 161,
        "current_material_id": 161,
        "material_version": "1790850188",
        "outdated": false,
        "outdated_reason": null,
        "kind": "course",
        "external_ref": "curso-77",
        "external_url": "https://escola.lmsestudio.com/cursos/77",
        "title": "Inglês para Viagem — Turma A",
        "status": "published",
        "parts": [
            {
                "index": 1,
                "title": "Módulo 2 — No aeroporto",
                "external_ref": "licao-301"
            }
        ],
        "on_behalf_of": {
            "external_user_id": "u-9",
            "name": "Coordenação da Escola"
        },
        "created_at": "2026-10-16T10:30:00-03:00",
        "updated_at": "2026-10-16T10:30:00-03:00"
    }
}
400 Envie o cabeçalho Idempotency-Key (um valor único por operação). application/problem+json
{
    "type": "about:blank",
    "title": "Bad Request",
    "status": 400,
    "detail": "Envie o cabeçalho `Idempotency-Key` (um valor único por operação).",
    "code": "idempotency_key_required"
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 A conta ainda não adquiriu este produto. Adquira para ler os materiais. application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A conta ainda não adquiriu este produto. Adquira para ler os materiais.",
    "code": "not_acquired"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
422 Dados inválidos (validation_failed) application/problem+json
{
    "type": "about:blank",
    "title": "Unprocessable Content",
    "status": 422,
    "detail": "Dados inválidos.",
    "code": "validation_failed",
    "errors": {
        "open_url_template": [
            "Precisa ser do mesmo domínio de `url`."
        ]
    }
}
GET /api/v1/publications

Publicações do aplicativo

Chave com publications:read

As publicações que este aplicativo registrou nesta conta (de todas as conexões dele), da mais recente para a mais antiga. Filtros product_id, material_id e status. Em páginas, por cursor. Use outdated para saber o que mudou no HotLearn depois de publicado. Com chave pessoal (do dono), a lista traz as publicações de todos os aplicativos da conta, só para leitura.

Cada publicação traz outdated, outdated_reason e current_material_id:

  • em dia: outdated: false, outdated_reason: null e current_material_id igual a material_id;
  • updated: a escola salvou o material de novo (a versão mudou);
  • personalized: a publicação saiu do original do acervo e a escola personalizou depois; a matriz dela agora é a cópia, com outro id (current_material_id).

Parâmetros

NomeTipoDescrição
product_idopcional integer Só deste produto.
material_idopcional integer Só deste material.
statusopcional string Situação.
limitopcional integer De 1 a 50 (padrão 12).
cursoropcional string O next_cursor da página anterior.

Exemplo

curl "https://hotlearn.com.br/api/v1/publications?status=published" \
  -H "Authorization: Bearer $HOTLEARN_KEY"

Respostas

200 Publicações application/json
{
    "data": [
        {
            "id": 15,
            "product": {
                "id": 136,
                "title": "Inglês para Viagem"
            },
            "material_id": 161,
            "current_material_id": 161,
            "material_version": "1790850188",
            "outdated": false,
            "outdated_reason": null,
            "kind": "course",
            "external_ref": "curso-77",
            "external_url": "https://escola.lmsestudio.com/cursos/77",
            "title": "Inglês para Viagem — Turma A",
            "status": "published",
            "parts": [
                {
                    "index": 1,
                    "title": "Módulo 2 — No aeroporto",
                    "external_ref": "licao-301"
                }
            ],
            "on_behalf_of": {
                "external_user_id": "u-9",
                "name": "Coordenação da Escola"
            },
            "created_at": "2026-10-16T10:30:00-03:00",
            "updated_at": "2026-10-16T10:30:00-03:00"
        },
        {
            "id": 12,
            "product": {
                "id": 136,
                "title": "Inglês para Viagem"
            },
            "material_id": 158,
            "current_material_id": 161,
            "material_version": "1789000000",
            "outdated": true,
            "outdated_reason": "personalized",
            "kind": "course",
            "external_ref": "curso-70",
            "external_url": "https://escola.lmsestudio.com/cursos/70",
            "title": "Inglês para Viagem — Turma piloto",
            "status": "published",
            "parts": [],
            "on_behalf_of": {
                "external_user_id": "u-9",
                "name": "Coordenação da Escola"
            },
            "created_at": "2026-10-10T09:00:00-03:00",
            "updated_at": "2026-10-10T09:00:00-03:00"
        }
    ],
    "next_cursor": null
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
403 Falta o escopo da rota (insufficient_scope) ou a conta está inativa (account_inactive) application/problem+json
{
    "type": "about:blank",
    "title": "Forbidden",
    "status": 403,
    "detail": "A chave não tem a permissão necessária: account:read.",
    "code": "insufficient_scope",
    "scopes": [
        "account:read"
    ]
}
PATCH /api/v1/publications/{publication}

Atualizar uma publicação

Chave com publications:write

Muda title, status (draft, published, archived) ou external_url. Só as publicações deste aplicativo; de outro, 404. Só esses três campos mudam (parts não). Não há DELETE: quando o curso for apagado do seu lado, mande PATCH com status: archived.

Parâmetros

NomeTipoDescrição
publicationobrigatório integer Identificador da publicação.

Exemplo

curl -X PATCH https://hotlearn.com.br/api/v1/publications/15 \
  -H "Authorization: Bearer $HOTLEARN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"archived"}'

Respostas

200 Atualizada application/json
{
    "data": {
        "id": 15,
        "product": {
            "id": 136,
            "title": "Inglês para Viagem"
        },
        "material_id": 161,
        "current_material_id": 161,
        "material_version": "1790850188",
        "outdated": false,
        "outdated_reason": null,
        "kind": "course",
        "external_ref": "curso-77",
        "external_url": "https://escola.lmsestudio.com/cursos/77",
        "title": "Inglês para Viagem — Turma A",
        "status": "archived",
        "parts": [
            {
                "index": 1,
                "title": "Módulo 2 — No aeroporto",
                "external_ref": "licao-301"
            }
        ],
        "on_behalf_of": {
            "external_user_id": "u-9",
            "name": "Coordenação da Escola"
        },
        "created_at": "2026-10-16T10:30:00-03:00",
        "updated_at": "2026-10-16T10:30:00-03:00"
    }
}
401 Chave ausente, inválida, vencida ou de conexão desfeita. unauthenticated: renove uma vez com a chave de renovação. connection_revoked: não renove; a escola desconectou, peça para conectar de novo. application/problem+json
{
    "type": "about:blank",
    "title": "Unauthorized",
    "status": 401,
    "detail": "Chave ausente, inválida ou vencida. Envie `Authorization: Bearer {chave}` ou renove a chave.",
    "code": "unauthenticated"
}
404 Não encontrado. application/problem+json
{
    "type": "about:blank",
    "title": "Not Found",
    "status": 404,
    "detail": "Não encontrado.",
    "code": "not_found"
}
422 Dados inválidos (validation_failed) application/problem+json
{
    "type": "about:blank",
    "title": "Unprocessable Content",
    "status": 422,
    "detail": "Dados inválidos.",
    "code": "validation_failed",
    "errors": {
        "open_url_template": [
            "Precisa ser do mesmo domínio de `url`."
        ]
    }
}

Documentação

Esta especificação.

GET /api/v1/openapi.json

Esta especificação (OpenAPI 3.1)

Sem chave de acesso

Para gerar clientes ou importar no Postman/Insomnia. Limite: 60 chamadas por minuto.

Exemplo

curl https://hotlearn.com.br/api/v1/openapi.json

Respostas

200 Especificação application/json