API de quizzes
Crie, leia e altere rascunhos, gerencie questões e publique versões usando o mesmo domínio seguro da aplicação web.
Base URL
/api/v1
Content-Type
application/json
Autorização
Bearer quiz_...
01 · Autenticação
Gere um token de acesso
A forma recomendada é gerar o token pela sua conta. Ele é exibido uma única vez: copie-o, guarde-o como segredo e envie-o no header Authorization das chamadas seguintes.
Pela interface da conta — recomendado
Entre na sua conta, abra Configurações, selecione Tokens e crie uma credencial para sua integração ou agente de IA.
Alternativa programática
Em um cliente sob seu controle, também é possível emitir o token diretamente pela API.
curl -X POST https://quizzes.alissonmachado.dev/api/v1/auth/tokens \
-H 'Content-Type: application/json' \
-d '{
"email": "voce@exemplo.com",
"password": "sua-senha",
"name": "Meu agente"
}'
{
"data": {
"id": "UUID_DO_TOKEN",
"name": "Meu agente",
"token": "quiz_SEGREDO_EXIBIDO_UMA_VEZ",
"token_type": "Bearer",
"scopes": ["quizzes:read", "quizzes:write", "quizzes:publish"],
"expires_at": null
}
}
curl https://quizzes.alissonmachado.dev/api/v1/quizzes \
-H 'Authorization: Bearer quiz_SEU_TOKEN'
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
quizzes:read |
scope | Leitura | Consulta quizzes, versões e valida rascunhos. |
quizzes:write |
scope | Escrita | Cria, importa e altera quizzes, rascunhos, questões e alternativas. |
quizzes:publish |
scope | Publicação | Publica uma versão validada. Todos os tokens criados atualmente recebem os três escopos. |
Revogue tokens pela tela de Configurações ou envie DELETE /api/v1/auth/token
com o mesmo header Authorization.
Usar com IA
Conecte um assistente de IA
Ao pedir que uma IA crie ou importe quizzes, envie o link desta página e peça que ela consulte os endpoints, a autenticação e o contrato JSON antes de agir. Compartilhe o token somente em uma ferramenta confiável e nunca em conversas públicas.
Link para compartilhar
https://quizzes.alissonmachado.dev/api/docs
Prompt sugerido
Consulte https://quizzes.alissonmachado.dev/api/docs antes de continuar. Siga a API v1 e use o
endpoint de importação descrito na documentação.
API REST direta
Funciona quando o assistente consegue fazer requisições HTTP para este domínio. As
versões web dos serviços de IA, porém, navegam por proxies com restrições próprias:
a chamada pode falhar com erros como Failed to fetch, sem nem retornar
um status HTTP.
Servidor MCP
O Model Context Protocol contorna essas restrições: o cliente de IA conecta o servidor como ferramenta nativa e chama a aplicação por conta própria, com o mesmo Bearer token e as mesmas regras de escopo e propriedade da API REST.
POST
/api/mcp
Bearer token
JSON-RPC 2.0
Servidor MCP stateless sobre o transporte Streamable HTTP. Aceita as mensagens initialize, ping,
tools/list
e tools/call; notificações respondem 202. GET e DELETE
retornam 405
— não há sessões nem streams SSE. Erros de domínio chegam
como resultado da ferramenta com isError: true
e o mesmo objeto error
da API REST em structuredContent.
| Ferramenta | Equivalente REST | Escopo | Descrição |
|---|---|---|---|
list_quizzes |
GET /quizzes | token válido | Lista os quizzes da conta com resumo das versões. |
get_quiz |
GET /quizzes/:id | token válido | Busca um quiz pelo ID. |
create_quiz |
POST /quizzes | quizzes:write | Cria um quiz em rascunho. |
import_quiz |
POST /quizzes/import | quizzes:write |
Importa um quiz completo; o argumento data usa o formato de importação.
|
set_quiz_active |
PATCH /quizzes/:id | quizzes:write | Ativa ou desativa um quiz. |
create_quiz_draft |
POST /quizzes/:id/drafts | quizzes:write | Garante um rascunho editável. |
get_quiz_version |
GET /quiz-versions/:id | token válido | Busca uma versão completa, com questões e alternativas. |
update_quiz_version |
PATCH /quiz-versions/:id | quizzes:write | Atualiza metadados de um rascunho. |
validate_quiz_version |
POST /quiz-versions/:id/validate | token válido | Valida um rascunho sem alterar nada. |
publish_quiz_version |
POST /quiz-versions/:id/publish | quizzes:publish | Publica um rascunho validado. |
create_question |
POST /quiz-versions/:id/questions | quizzes:write | Cria uma questão no rascunho. |
update_question |
PATCH /questions/:id | quizzes:write |
Atualiza uma questão; options omitido preserva as alternativas.
|
delete_question |
DELETE /questions/:id | quizzes:write | Remove uma questão do rascunho. |
curl -X POST https://quizzes.alissonmachado.dev/api/mcp \
-H 'Authorization: Bearer quiz_SEU_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {"name": "list_quizzes", "arguments": {}}
}'
Como conectar em cada assistente
Na interface web (claude.ai)
O caminho mais simples é liberar este domínio para chamadas diretas:
-
Abra Configurações → Conexões de rede
e adicione
quizzes.alissonmachado.devaos domínios permitidos. - Abra uma conversa nova — a permissão não vale para conversas já iniciadas.
- Envie o link desta documentação e um token; o Claude passa a chamar a API REST diretamente.
No Claude Code (terminal, desktop ou claude.ai/code)
Conecte o servidor MCP com o token no header:
claude mcp add --transport http quizzes https://quizzes.alissonmachado.dev/api/mcp \
--header "Authorization: Bearer quiz_SEU_TOKEN"
Os conectores personalizados de Configurações → Conectores autenticam por OAuth e não aceitam um header Bearer próprio; para esta API, use as duas opções acima.
Sem suporte a MCP na interface web
O chat do ChatGPT não permite liberar domínios para acesso direto nem conectar servidores MCP autenticados por Bearer token. A navegação passa por um proxy próprio, então chamadas a esta API tendem a falhar sem retornar um status HTTP. O caminho que funciona é um GPT personalizado com Actions: as chamadas partem dos servidores da OpenAI, fora do proxy de navegação.
GPT personalizado com Actions — schema pronto para importar
Esta aplicação publica o schema OpenAPI da API v1, então não é preciso escrever nada à mão:
URL do schema
https://quizzes.alissonmachado.dev/api/openapi.json
- No ChatGPT (recurso de planos pagos), abra GPTs → Criar e vá à aba Configurar → Ações → Criar nova ação.
- Escolha Importar de URL e cole o endereço do schema acima.
-
Em Autenticação, selecione Chave de API
com tipo Bearer
e cole um token
quiz_...criado em Configurações → Tokens. - Em Compartilhar, mantenha o acesso como Somente eu. Salve e converse com o GPT: ele passa a listar, criar, validar e publicar quizzes pela API REST. Ações de escrita pedem sua confirmação antes de executar.
Por que o GPT deve ficar privado
O token fica embutido na Action e é usado em todas as chamadas, seja quem for que estiver conversando com o GPT. Como todo token desta API carrega hoje os três escopos — leitura, escrita e publicação —, compartilhar o GPT por link ou na GPT Store entrega sua conta junto: qualquer pessoa poderia criar, alterar e publicar quizzes em seu nome, e os registros mostrariam você como autor, sem como distinguir quem realmente fez cada chamada. Compartilhar também exige publicar uma política de privacidade para o domínio da Action — mais um sinal de que esse fluxo foi pensado para expor um serviço ao público, não uma conta pessoal.
Se suspeitar que o token vazou, revogue-o em Configurações → Tokens: o acesso do GPT morre na hora. Enquanto não houver tokens de escopo reduzido, trate qualquer GPT com Action desta API como estritamente pessoal.
Em aplicações próprias, a Responses API da OpenAI também aceita servidores MCP
remotos com headers personalizados — aponte para https://quizzes.alissonmachado.dev/api/mcp.
Sem conectores no app web
O app web do Gemini não oferece conectores MCP personalizados nem liberação de domínios para chamadas diretas.
Gemini CLI
O
Gemini CLI
— agente oficial do Google para o terminal, lançado em 2025 — conecta servidores
MCP. Adicione ao ~/.gemini/settings.json:
{
"mcpServers": {
"quizzes": {
"httpUrl": "https://quizzes.alissonmachado.dev/api/mcp",
"headers": {
"Authorization": "Bearer quiz_SEU_TOKEN"
}
}
}
}
Depois abra o gemini
e rode /mcp
para confirmar que as ferramentas foram carregadas.
02 · Contratos
Formato das requisições e respostas
Todos os corpos usam JSON em UTF-8. IDs são UUIDs; datas usam ISO 8601; valores
decimais como total_points e weight retornam como strings.
Sucesso
Respostas com conteúdo usam {"data": ...}. Exclusões bem-sucedidas usam
204 No Content
sem corpo.
Atualizações
Corpos de PATCH são parciais. Campos desconhecidos são ignorados.
Envie apenas os campos que deseja alterar.
Propriedade
A API mostra somente recursos da conta autenticada. Um recurso inexistente ou de
outra conta retorna o mesmo 404.
Modelos retornados
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
id |
UUID | Sempre | Identificador do agrupador do quiz. |
public_slug |
string | Sempre |
Slug do link público em /q/:public_slug.
|
active |
boolean | Sempre |
Se false, o link existe, mas não aceita novas respostas.
|
inserted_at |
datetime | Sempre | Data de criação. |
updated_at |
datetime | Sempre | Última alteração. |
versions |
VersionSummary[] | Sempre |
Versões da mais recente para a mais antiga. Cada item tem id, version_number, name, status,
published_at
e updated_at.
|
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
id |
UUID | Sempre | Identificador da versão. |
quiz_id |
UUID | Sempre | Identificador do quiz pai. |
version_number |
integer | Sempre | Começa em 1 e cresce a cada novo rascunho. |
name |
string | Sempre | Título do quiz. |
description |
string | Sempre | Descrição; pode ser vazia. |
total_points |
decimal string | Sempre |
Exemplo: "100" ou "7.5".
|
unequal_weights |
boolean | Sempre | Permite pesos diferentes entre questões. |
question_order_mode |
enum | Sempre |
fixed, random ou ai.
|
status |
enum | Sempre |
draft ou published.
|
published_at |
datetime | null | Sempre | Nulo enquanto for rascunho. |
changelog |
string[] | Sempre | Resumo de alterações gerado na publicação. |
inserted_at |
datetime | Sempre | Data de criação. |
updated_at |
datetime | Sempre | Última alteração. |
questions |
Question[] | Sempre |
Questões ordenadas por position.
|
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
id |
UUID | Sempre | Identificador desta questão na versão. |
identity_key |
UUID | Sempre | Identidade estável da questão entre versões. |
position |
integer | Sempre | Posição iniciada em zero. |
statement |
string | Sempre | Enunciado. |
type |
enum | Sempre |
true_false, single, multiple
ou text.
|
allow_partial_credit |
boolean | Sempre |
Usado em questões multiple.
|
true_false_answer |
boolean | null | Sempre |
Resposta de questões true_false.
|
editor_note |
string | null | Sempre | Resposta de referência e explicação. |
weight |
decimal string | null | Sempre |
Peso quando unequal_weights estiver ativo.
|
annulled |
boolean | Sempre | Informa se a questão foi anulada. |
annulled_reason |
string | null | Sempre | Motivo da anulação. |
options |
Option[] | Sempre | Lista vazia para questões sem alternativas. |
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
id |
UUID | Sempre | Identificador da alternativa. |
identity_key |
UUID | Sempre | Identidade estável entre versões. |
position |
integer | Sempre | Posição iniciada em zero. |
text |
string | Sempre | Texto exibido ao participante. |
correct |
boolean | Sempre | Se a alternativa compõe o gabarito. |
{
"data": {
"id": "VERSION_UUID",
"quiz_id": "QUIZ_UUID",
"version_number": 1,
"name": "Fundamentos de Elixir",
"description": "Conceitos básicos",
"total_points": "100",
"unequal_weights": false,
"question_order_mode": "fixed",
"status": "draft",
"published_at": null,
"changelog": [],
"inserted_at": "2026-07-04T21:00:00Z",
"updated_at": "2026-07-04T21:00:00Z",
"questions": [
{
"id": "QUESTION_UUID",
"identity_key": "STABLE_QUESTION_UUID",
"position": 0,
"statement": "Elixir roda na BEAM?",
"type": "true_false",
"allow_partial_credit": false,
"true_false_answer": true,
"editor_note": "Sim, Elixir compila para bytecode da BEAM.",
"weight": null,
"annulled": false,
"annulled_reason": null,
"options": []
}
]
}
}
03 · Referência
Endpoints e parâmetros
Abra uma rota para ver corpo, regras e resposta. Todas exigem Bearer token, exceto a
emissão inicial em POST /auth/tokens.
Quizzes
GET
/api/v1/quizzes
token válido
200 · Quiz[]
Lista os quizzes da conta, do mais recente para o mais antigo. Não recebe query params nem paginação atualmente. Cada quiz inclui resumos das suas versões.
Resposta: {"data": [Quiz, ...]}
POST
/api/v1/quizzes
quizzes:write
201 · Version
Cria um quiz e sua versão 1 em estado draft. O corpo pode ser vazio;
nome e questões são exigidos apenas para publicar.
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
name |
string | Opcional · padrão vazio | Título do quiz. |
description |
string | Opcional · padrão vazio | Descrição do quiz. |
total_points |
number | decimal string | Opcional · padrão 100 | Precisa ser maior que zero. |
unequal_weights |
boolean | Opcional · padrão false | Ativa pesos por questão. |
question_order_mode |
enum | Opcional · padrão fixed |
fixed, random ou ai.
|
Resposta:
versão completa, incluindo quiz_id
e questions: [].
POST
/api/v1/quizzes/import
quizzes:write
201 · Version
Cria um rascunho completo em uma chamada. Este endpoint usa deliberadamente chaves em português e o mesmo formato do importador da interface.
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
nome |
string | Obrigatório | Não pode estar vazio. |
descricao |
string | Opcional · padrão vazio | Descrição do quiz. |
nota_total |
number > 0 | Opcional · padrão 100 | Nota máxima. |
pesos_desiguais |
boolean | Opcional · padrão false |
Permite peso por questão.
|
modo_ordem |
enum | Opcional · padrão fixa |
fixa, aleatoria ou ia.
|
questoes |
QuestãoImportada[] | Obrigatório | Lista com pelo menos uma questão. |
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
enunciado |
string | Obrigatório | Não pode estar vazio. |
tipo |
enum | Obrigatório |
verdadeiro_falso, unica, multipla
ou discursiva.
|
resposta_verdadeiro_falso |
boolean | Obrigatório em verdadeiro_falso | Gabarito da afirmação. |
alternativas |
AlternativaImportada[] | Obrigatório em unica/multipla |
Ao menos 2 itens com texto e correta.
|
nota_parcial |
boolean | Opcional em multipla | Concede crédito proporcional quando não houver marcação errada. |
resposta_referencia |
string | Opcional | Explicação e referência para correção discursiva por IA. |
peso |
number >= 0 | Opcional |
Usado quando pesos_desiguais for verdadeiro.
|
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
texto |
string | Obrigatório | Texto da alternativa. |
correta |
boolean | Opcional · padrão false | Marca a alternativa como parte do gabarito. |
Em unica, exatamente uma alternativa deve ter correta: true;
em multipla, pelo menos uma. Chaves desconhecidas são ignoradas.
GET
/api/v1/quizzes/:id
token válido
200 · Quiz
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
id |
UUID | Obrigatório | ID do quiz, não da versão. |
Resposta: quiz com a lista de resumos das versões. O conteúdo das questões não vem nesta rota.
PATCH
/api/v1/quizzes/:id
quizzes:write
200 · Quiz
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
active |
boolean | Obrigatório |
false impede novas respostas; true reabre o quiz.
|
Ausência ou tipo incorreto em active
retorna 422 validation_error.
POST
/api/v1/quizzes/:id/drafts
quizzes:write
201 · Version
Retorna o rascunho existente. Se não houver um, copia a versão publicada mais
recente para a próxima version_number, preservando identidades de questões
e alternativas. Não recebe body.
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
id |
UUID | Obrigatório | ID do quiz. |
Versões e publicação
GET
/api/v1/quiz-versions/:id
token válido
200 · Version
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
id |
UUID | Obrigatório |
ID da versão obtido em Quiz.versions.
|
Retorna a versão completa, com todas as questões e alternativas.
PATCH
/api/v1/quiz-versions/:id
quizzes:write
200 · Version
Edita somente rascunhos. Todos os campos são opcionais e a resposta traz a versão completa recarregada.
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
name |
string | Opcional | Título. |
description |
string | Opcional | Descrição. |
total_points |
number | decimal string | Opcional | Precisa ser maior que zero. |
unequal_weights |
boolean | Opcional | Ativa pesos por questão. |
question_order_mode |
enum | Opcional |
fixed, random ou ai.
|
POST
/api/v1/quiz-versions/:id/validate
token válido
200 · Validation
Executa as mesmas regras da publicação sem alterar nada. Uma validação
negativa ainda retorna HTTP 200; consulte data.valid. Não recebe body.
{
"data": {
"valid": false,
"errors": ["O quiz precisa de um nome", "O quiz precisa de pelo menos uma questão"]
}
}
POST
/api/v1/quiz-versions/:id/publish
quizzes:publish
200 · Version
Valida, publica e congela o rascunho. Também gera tags internas de IA e o changelog.
Não recebe body. Se houver problemas de conteúdo, retorna 422 com todos
os erros em error.details.
Questões e alternativas
POST
/api/v1/quiz-versions/:id/questions
quizzes:write
201 · Question
Adiciona uma questão ao fim do rascunho. A posição é atribuída automaticamente. O endpoint permite salvar incompleto; use a validação antes de publicar.
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
statement |
string | Opcional · padrão vazio | Enunciado. |
type |
enum | Opcional · padrão single |
true_false, single, multiple
ou text.
|
allow_partial_credit |
boolean | Opcional · padrão false |
Use apenas com multiple.
|
true_false_answer |
boolean | null | Exigido para publicar true_false | Gabarito verdadeiro/falso. |
editor_note |
string | null | Opcional | Explicação ou resposta de referência. |
weight |
number | decimal string | null | Opcional | Peso da questão. |
options |
OptionInput[] | Opcional · padrão [] |
Alternativas com text, correct e position.
|
{
"statement": "Quais valores são booleanos?",
"type": "multiple",
"allow_partial_credit": true,
"editor_note": "true e false são os booleanos de Elixir.",
"options": [
{"text": "true", "correct": true, "position": 0},
{"text": "false", "correct": true, "position": 1},
{"text": "nil", "correct": false, "position": 2}
]
}
PATCH
/api/v1/questions/:id
quizzes:write
200 · Question
Atualiza uma questão de rascunho. Aceita os mesmos campos da criação, além de position. Se
options
for omitido, as alternativas permanecem;
se for enviado, ele substitui a coleção inteira.
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
options[].id |
UUID | Para manter uma alternativa | IDs existentes preservam identidade e atualizam o item. |
options[].text |
string | Opcional | Texto da alternativa. |
options[].correct |
boolean | Opcional · padrão false | Participa do gabarito. |
options[].position |
integer | Opcional · padrão 0 | Ordem da alternativa. |
Atenção: alternativas existentes omitidas da lista enviada são excluídas; itens sem
id
são criados como novas alternativas.
DELETE
/api/v1/questions/:id
quizzes:write
204 · sem corpo
Remove a questão de um rascunho e renumera as posições restantes. Questões de versões publicadas não podem ser removidas.
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
id |
UUID | Obrigatório |
ID da questão, não o identity_key.
|
Token atual
DELETE
/api/v1/auth/token
token válido
204 · sem corpo
Revoga imediatamente o Bearer token usado nesta requisição. As demais credenciais da conta continuam ativas. Não recebe path params nem body.
04 · Fluxo recomendado
Do rascunho à publicação
-
1 · CRIAR
POST /quizzesouPOST /quizzes/importGuarde
data.idcomo VERSION_ID edata.quiz_idcomo QUIZ_ID. -
2 · EDITAR
PATCH /quiz-versions/VERSION_IDAjuste metadados e adicione questões enquanto o status for
draft. -
3 · VALIDAR
POST /quiz-versions/VERSION_ID/validateProssiga apenas quando
data.validfortrue. -
4 · PUBLICAR
POST /quiz-versions/VERSION_ID/publishA versão se torna imutável. Use
POST /quizzes/QUIZ_ID/draftspara a próxima edição.
05 · Erros
Códigos e formatos de falha
| Campo | Tipo | Presença | Descrição |
|---|---|---|---|
401 unauthorized |
error object | Token ausente, inválido, revogado ou expirado |
Inclui WWW-Authenticate: Bearer realm="quiz-api".
|
401 invalid_credentials |
error object | Falha ao emitir token | E-mail ou senha inválidos. |
403 insufficient_scope |
error object | Escopo ausente |
Inclui required_scope.
|
404 not_found |
error object | Ausente ou de outra conta | Não revela a existência de recursos alheios. |
409 version_not_editable |
error object | Estado incompatível | Operação de escrita em versão publicada. |
409 published_version_required |
error object | Sem base para novo rascunho | Não existe versão publicada para copiar. |
422 validation_error |
error + details[] | Parâmetros ou conteúdo inválidos |
As mensagens legíveis ficam em error.details.
|
422 operation_failed |
error object | Falha não classificada | A operação não pôde ser concluída. |
{
"error": {
"code": "validation_error",
"details": [
"Questão 1: precisa de pelo menos 2 alternativas",
"Questão 1: marque exatamente 1 alternativa correta"
]
}
}