Simples, rápido e confiável.
Cada conta recebe uma chave prefixada qb_ gerada com 40 caracteres aleatórios seguros.
Gráfico de barras com consumo diário dos últimos 30 dias, custo mensal e histórico de pagamentos.
O gateway bloqueia PUT, POST e DELETE. Apenas GET é permitido, protegendo integralmente a base de dados.
O acesso à API privada usa token com cache de 23h — zero overhead de autenticação por requisição.
Cadastro exige CPF válido e único, prevenindo criação de múltiplas contas por um mesmo usuário.
Pagamento mensal via PIX com QR Code no último dia do mês. Histórico de pagamentos disponível na dashboard.
Base URL: https://qapi.otunac.com/api · Header obrigatório: Q-Api-Key: qb_SuaChave
Todos os endpoints de consulta requerem uma API Key enviada no header HTTP Q-Api-Key. Você obtém sua chave ao criar uma conta — ela fica disponível no seu dashboard.
Q-Api-Key: qb_SuaChaveAqui
A chave é prefixada com qb_ seguido de 40 caracteres aleatórios. Mantenha-a em segredo — nunca exponha em código público ou repositórios. Se necessário, redefina-a pelo suporte.
Os endpoints que retornam listas suportam paginação via query parameters. Todos seguem o mesmo padrão de resposta com metadados de paginação.
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
| page | integer | 1 | Número da página (começa em 1) |
| size | integer | 10 | Itens por página. Em /questions, máximo de 100 |
{
"page": 1, // página atual
"size": 10, // itens nesta página
"pages": 63, // total de páginas
"total": 624, // total de itens encontrados
"questoes": [/* array de itens */]
}
Para percorrer todos os resultados, itere de page=1 até page=pages. Cada página consome 1 requisição no seu billing.
Endpoint principal para consulta de questões com filtros opcionais e paginação. Limite máximo de 100 itens por página. Combine múltiplos filtros para refinar os resultados — todos os filtros são cumulativos (AND).
| Parâmetro | Tipo | Req. | Descrição |
|---|---|---|---|
| page | integer | — | Página (padrão: 1) |
| size | integer | — | Itens por página — máximo 100 (padrão: 10) |
| banca | string | — | Banca organizadora. Use /api/bancas para listar valores válidos |
| orgao | string | — | Órgão da prova. Use /api/orgaos para listar valores válidos |
| cargo | string | — | Cargo da prova. Use /api/cargos para listar valores válidos |
| materia | string | — | Disciplina/matéria. Use /api/materias para listar valores válidos |
| assunto | string | — | Assunto específico da matéria. Use /api/assuntos para listar |
| ano | integer | — | Ano de realização da prova (ex: 2024) |
GET https://qapi.otunac.com/api/questoes?page=1&size=10&banca=FGV&ano=2024 Q-Api-Key: qb_SuaChaveAqui
{
"page": 1,
"size": 10,
"pages": 63,
"total": 624,
"questoes": [
{
"_id": "69a8224af6d9445ec04dad9c",
"orgao": "TJ/SE",
"banca": "FGV",
"ano": 2023,
"cargo": "Analista Judiciário - Análise de Sistemas",
"materia": "Conhecimento Específico",
"assunto": "Arquitetura de Computadores",
"enunciado":"Em sistemas operacionais, a métrica que mede...",
"opcaoA": "throughput;",
"opcaoB": "tempo de espera;",
"opcaoC": "tempo de turnaround;",
"opcaoD": "tempo de processador;",
"opcaoE": "utilização do processador.",
"gabarito": "A",
"comentario":"Throughput é o número de processos...",
"texto": "QTXT566467" // código p/ buscar o texto em /api/texts/:codigo
}
]
}
## cURL curl -X GET \ "https://qapi.otunac.com/api/questoes?banca=FGV&materia=Direito+Administrativo&page=1&size=20" \ -H "Q-Api-Key: qb_SuaChaveAqui" ## Python import requests r = requests.get( "https://qapi.otunac.com/api/questoes", params={"banca": "FGV", "materia": "Direito Administrativo", "page": 1, "size": 20}, headers={"Q-Api-Key": "qb_SuaChaveAqui"} ) data = r.json() print(f"Total: {data['total']} questões, {data['pages']} páginas") ## JavaScript const params = new URLSearchParams({ banca: "FGV", materia: "Direito Administrativo", page: 1, size: 20 }); const r = await fetch(`https://qapi.otunac.com/api/questoes?${params}`, { headers: { "Q-Api-Key": "qb_SuaChaveAqui" } }); const data = await r.json();
/api/questions
Recupera o texto completo referenciado pelo campo texto de uma questão. Questões que não possuem texto base retornam esse campo como string vazia — verifique antes de fazer a chamada.
| Parâmetro | Tipo | Req. | Descrição |
|---|---|---|---|
| codigo | string | ✓ Sim | Código do texto — valor do campo texto retornado em /questoes |
GET https://qapi.otunac.com/api/textos/QTXT566467 Q-Api-Key: qb_SuaChaveAqui
{
"_id": "69b0cfaa20dadd7d66bfcec9",
"codigo": "QTXT566467",
"titulo": "A reinvenção da vírgula",
"texto": "No começo de 1902, Machado de Assis...",
"fonte": "Machado de Assis",
"createdAt": "2026-03-11T02:12:58.079Z"
}
## Python — buscar questão e carregar seu texto base import requests BASE = "https://qapi.otunac.com/api" headers = {"Q-Api-Key": "qb_SuaChaveAqui"} questoes = requests.get(f"{BASE}/questoes", params={"banca": "FGV"}, headers=headers).json() for q in questoes["questoes"]: if q["texto"]: # campo não vazio → tem texto base txt = requests.get(f"{BASE}/textos/{q['texto']}", headers=headers).json() print(txt["titulo"], txt["texto"][:200])
/api/texts/:codigo
Lista e consulta provas cadastradas no sistema — cada prova agrupa as questões de um exame identificado por banca, órgão, cargo e ano. O campo linkProva aponta para o PDF do exame e linkGabarito para o gabarito oficial, quando disponíveis.
| Parâmetro | Tipo | Req. | Descrição |
|---|---|---|---|
| page | integer | — | Página (padrão: 1) |
| size | integer | — | Itens por página, máx. 100 (padrão: 10) |
| banca | string | — | Filtrar por banca organizadora |
| orgao | string | — | Filtrar por órgão |
| cargo | string | — | Filtrar por cargo |
| ano | integer | — | Filtrar por ano do exame |
GET https://qapi.otunac.com/api/provas?banca=CEBRASPE&ano=2024&page=1&size=10 Q-Api-Key: qb_SuaChaveAqui
{
"provas": [
{
"_id": "6a164c795e06528a230ff9d4",
"orgao": "Polícia Federal",
"banca": "CEBRASPE",
"cargo": "Delegado Federal",
"ano": 2024,
"linkProva": "https://cdn.exemplo.com/prova.pdf",
"linkGabarito": "https://cdn.exemplo.com/gabarito.pdf",
"createdAt": "2025-05-30T14:00:00.000Z"
}
],
"total": 12,
"page": 1,
"size": 10,
"pages": 2
}
| Parâmetro | Tipo | Req. | Descrição |
|---|---|---|---|
| id | string | ✓ Sim | ID da prova (ObjectId MongoDB) |
GET https://qapi.otunac.com/api/provas/6a164c795e06528a230ff9d4 Q-Api-Key: qb_SuaChaveAqui
{
"_id": "6a164c795e06528a230ff9d4",
"orgao": "Polícia Federal",
"banca": "CEBRASPE",
"cargo": "Delegado Federal",
"ano": 2024,
"linkProva": "https://cdn.exemplo.com/prova.pdf",
"linkGabarito": "https://cdn.exemplo.com/gabarito.pdf",
"uploadProva": { "filename": "pf_2024.pdf", "size": 2048576, "uploadedAt": "2025-05-30T14:00:00.000Z" },
"uploadGabarito": { "filename": "gabarito_pf_2024.pdf", "size": 512000, "uploadedAt": "2025-05-30T15:00:00.000Z" },
"createdAt": "2025-05-30T14:00:00.000Z"
}
404 quando o ID não existe.
Os campos linkProva e linkGabarito são null quando o PDF ainda não foi enviado.
Use esses endpoints para descobrir os valores válidos dos filtros de /api/questions. Todos suportam paginação e busca por texto. O parâmetro search realiza busca parcial case-insensitive.
Lista as bancas organizadoras. Use search para filtrar por nome.
GET https://qapi.otunac.com/api/bancas?page=1&size=10&search=fgv Q-Api-Key: qb_SuaChaveAqui
{
"bancas": ["FGV"],
"total": 1, "page": 1, "pages": 1
}
Lista os órgãos. Use search para busca parcial.
GET https://qapi.otunac.com/api/orgaos?page=1&size=5&search=ces Q-Api-Key: qb_SuaChaveAqui
{
"orgaos": ["CESPE", "CESGRANRIO"],
"total": 2, "page": 1, "pages": 1
}
Lista os cargos disponíveis na base.
GET https://qapi.otunac.com/api/cargos?page=1&size=10&search=professor Q-Api-Key: qb_SuaChaveAqui
{
"cargos": ["Professor de Ensino Básico", "Professor Adjunto"],
"total": 2, "page": 1, "pages": 1
}
Lista as matérias e disciplinas disponíveis.
GET https://qapi.otunac.com/api/materias?page=1&size=5&search=Direito Q-Api-Key: qb_SuaChaveAqui
{
"materias": ["Direito Administrativo", "Direito Constitucional", "Direito Civil"],
"total": 3, "page": 1, "pages": 1
}
Lista os assuntos de uma matéria. materia é obrigatório.
| Parâmetro | Tipo | Req. | Descrição |
|---|---|---|---|
| materia | string | ✓ Sim | Nome exato da matéria (obter via /api/materias) |
| page | integer | — | Página |
| size | integer | — | Itens por página |
| search | string | — | Busca parcial no nome do assunto |
GET https://qapi.otunac.com/api/assuntos?materia=Tecnologia+Java&page=1&size=5&search=hibernate Q-Api-Key: qb_SuaChaveAqui
{
"materia": "Tecnologia Java",
"assuntos": ["Hibernate / JPA", "Hibernate Cache"],
"total": 2, "page": 1, "pages": 1
}
Endpoints para criar conta e obter token via API. Útil para integrações automatizadas. O CPF brasileiro válido é obrigatório no cadastro — cada CPF pode ter apenas uma conta.
Cria uma nova conta e retorna a api_key gerada automaticamente — prefixada com qb_.
| Campo | Tipo | Req. | Descrição |
|---|---|---|---|
| name | string | ✓ | Nome completo |
| string | ✓ | E-mail único (usado no login) | |
| cpf | string | ✓ | CPF brasileiro válido (formato: 123.456.789-09 ou apenas dígitos) |
| password | string | ✓ | Senha com mínimo de 8 caracteres |
POST https://qapi.otunac.com/api/auth/register Content-Type: application/json { "name": "João Silva", "email": "[email protected]", "cpf": "123.456.789-09", "password": "minhasenha123" }
{
"message": "Conta criada com sucesso.",
"api_key": "qb_abc123xyz..." // guarde esta chave!
}
Autentica com e-mail e senha. Retorna um JWT Bearer token e os dados da conta, incluindo a api_key.
| Campo | Tipo | Req. | Descrição |
|---|---|---|---|
| string | ✓ | E-mail cadastrado | |
| password | string | ✓ | Senha da conta |
POST https://qapi.otunac.com/api/auth/login Content-Type: application/json { "email": "[email protected]", "password": "minhasenha123" }
{
"token": "eyJhbGci...", // JWT — válido por 24h
"api_key": "qb_abc123xyz...",
"api_key_active": true
}
O JWT retornado pode ser usado como Authorization: Bearer <token> em rotas autenticadas da web. Para acesso à API de questões, use sempre o Q-Api-Key header com sua api_key.
A API retorna erros em formato JSON com um campo error descritivo. Use o HTTP status code para determinar o tipo de falha.
| Status | Significado | Causa comum |
|---|---|---|
| 200 | OK | Requisição processada com sucesso |
| 400 | Bad Request | Parâmetro inválido ou ausente (ex: materia ausente em /assuntos) |
| 401 | Unauthorized | Header Q-Api-Key ausente ou inválido |
| 403 | Forbidden | Chave de API suspensa por inadimplência |
| 404 | Not Found | Recurso não encontrado (ex: código de texto inexistente) |
| 422 | Unprocessable | Dado inválido no corpo (registro/login) |
| 500 | Server Error | Erro interno — tente novamente ou contate o suporte |
{
"error": "Chave de API inválida ou inexistente."
}
import requests r = requests.get( "https://qapi.otunac.com/api/questions", headers={"Q-Api-Key": "qb_SuaChave"} ) if r.status_code == 200: data = r.json() elif r.status_code == 401: raise ValueError("API Key inválida") elif r.status_code == 403: raise PermissionError("Chave suspensa — regularize o pagamento") else: r.raise_for_status()
Sem mensalidade, sem taxa de adesão. A cobrança é calculada com base no total de requisições realizadas via sua API Key no mês. O pagamento é feito no último dia de cada mês via PIX.