Como começar
A API é somente leitura. Ela permite consultar as solicitações de autógrafo já conferidas e receber avisos automáticos quando algo muda. Não há nenhum endpoint de escrita: nenhum sistema externo cria, altera ou apaga dados.
1. Peça um token
Os tokens são gerados pela administração, na aba API do sistema. Cada sistema integrado deve ter o seu, para que o acesso possa ser revogado individualmente. O token aparece uma única vez, no momento da criação — guarde-o em cofre de segredos, nunca no código-fonte.
2. Endereço base
https://SEU-DOMINIO/v1
3. Autentique cada chamada
Envie o token no cabeçalho Authorization, no formato Bearer:
# primeira chamada: confirma que o token funciona
curl -H "Authorization: Bearer agab_seu_token_aqui" \
https://SEU-DOMINIO/v1/estatisticas
Os dados são pessoais de terceiros. Nome, telefone e e-mail de quem comprou um livro num evento estão sujeitos à LGPD, e foram coletados com a finalidade declarada na própria ficha: enviar informações sobre o autor e organizar a entrega dos exemplares assinados. Ao integrar, você assume as obrigações de quem trata esses dados: finalidade restrita a essa, acesso controlado, transmissão em HTTPS e prazo de guarda definido. Não replique essa base para mailing genérico.
Consulta
/v1/solicitacoes
lista pedidos, com filtros e paginação
/v1/solicitacoes/{id}
um pedido específico
/v1/estatisticas
totais por livro, situação e evento
Parâmetros de /v1/solicitacoes
| Parâmetro | Tipo | Descrição |
|---|---|---|
q | texto | Busca livre no nome da dedicatória, no comprador, e-mail, telefone, título do livro e evento. Ignora acentos: q=jose encontra "José". |
livro | enum | Chave do livro. Só traz pedidos que incluam esse título. Lista completa em Modelo de dados. |
status | enum | pendente, assinado, entregue, cancelado |
evento | texto | Filtra pelo evento de origem (busca parcial). |
desde | data ISO | Só pedidos criados a partir desta data. Ex.: 2026-08-01 |
limite | inteiro | Itens por página. Padrão 50, máximo 200. |
offset | inteiro | Quantos pular. Use com total para paginar. |
Exemplo
# pedidos de "Visões do Cosmos" ainda não assinados
curl -H "Authorization: Bearer $TOKEN" \
"https://SEU-DOMINIO/v1/solicitacoes?livro=visoes_do_cosmos&status=pendente&limite=20"
{
"total": 37,
"limite": 20,
"offset": 0,
"solicitacoes": [ /* ver Modelo de dados */ ]
}
total é a contagem de todos os pedidos que casam com o filtro,
não o tamanho desta página. Para percorrer tudo, incremente offset de
limite em limite enquanto offset < total.
Modelo de dados
Campos sem valor vêm como null, nunca como string vazia. Listas vêm
sempre como array, possivelmente vazio.
{
"id": "62a64bbe-8f82-473a-b14f-69a3e4548de8",
"autografo": {
"nome": "Nathalia e Junior",
"nomes": ["Nathalia", "Junior"]
},
"livros": [
{ "chave": "missao", "titulo": "Missão" }
],
"exemplares": 1,
"comprador": {
"nome": "Ailton Moura",
"telefone": "+55 (65) 99606-7966",
"email": "megaautomacao@exemplo.com"
},
"origem": {
"evento": "Feira do Livro de Cuiabá",
"local": "Centro de Eventos, Cuiabá/MT",
"data_pedido": "2026-08-26",
"registrado_por": "Maria Souza"
},
"status": "pendente",
"observacoes": null,
"confianca_leitura": 0.94,
"tem_ficha_digitalizada": true,
"criado_em": "2026-08-26T19:15:21.929Z",
"atualizado_em": "2026-08-26T19:15:21.929Z"
}
Sobre autografo.nome e autografo.nomes
nome é o texto exatamente como foi pedido na ficha — é ele que
vai escrito na dedicatória, inclusive o "e" entre dois nomes. nomes traz os
mesmos nomes separados um a um, para contagem e busca. Uma ficha pode pedir mais de
uma dedicatória para o mesmo exemplar.
Valores de livros[].chave
missao, e_possivel, gagarin, menino_pais_prof,
menino, visoes_do_cosmos. O campo é uma lista: a mesma ficha
pode marcar mais de um título. exemplares traz a quantidade total de livros
do pedido, que pode ser maior que o número de títulos.
Valores de status
| Valor | Significado |
|---|---|
pendente | Conferido pelo gabinete, aguardando a assinatura do senador. |
assinado | Livro assinado, aguardando entrega ou envio. |
entregue | Entregue a quem pediu. Ciclo encerrado. |
cancelado | Pedido desfeito (desistência, duplicidade, ficha inválida). |
Sobre confianca_leitura
Número de 0 a 1 informado pela IA que leu a ficha manuscrita, ou null.
Todo pedido disponível na API já passou por conferência humana, mas esse valor ajuda
a priorizar auditorias — abaixo de 0,75 vale reconferir contra a imagem.
As imagens das fichas não são expostas pela API.
tem_ficha_digitalizada apenas informa que existe uma, para o caso de alguém
precisar solicitá-la à administração.
Webhooks
Em vez de ficar consultando a API em busca de novidades, cadastre uma URL e nós avisamos. A administração cadastra o webhook na aba API do sistema, informando o nome, a URL e quais eventos interessam.
Eventos
| Evento | Quando dispara |
|---|---|
solicitacao.criada | Uma ficha foi conferida e virou pedido definitivo. |
solicitacao.atualizada | Algum campo de um pedido existente mudou — inclusive a passagem para assinado ou entregue. |
solicitacao.excluida | Um pedido foi apagado. O corpo traz só id e nome. |
O que chega na sua URL
Um POST com content-type: application/json e estes cabeçalhos:
| Cabeçalho | Conteúdo |
|---|---|
x-evento | Nome do evento, ex.: solicitacao.criada |
x-entrega-id | UUID único desta entrega. Use para descartar duplicatas. |
x-assinatura | sha256=<hex> — HMAC-SHA256 do corpo. Sempre valide. |
{
"evento": "solicitacao.criada",
"enviado_em": "2026-08-26T19:15:22.100Z",
"dados": { /* mesmo formato de /v1/solicitacoes/{id} */ }
}
Regras de entrega
- Responda 2xx em até 10 segundos. Fora disso, contamos como falha.
- Responda rápido e processe depois: enfileire internamente em vez de trabalhar antes de responder.
- Após 10 falhas seguidas o webhook é desativado automaticamente e precisa ser reativado pela administração. Uma entrega bem-sucedida zera o contador.
- Não há reenvio automático de uma entrega isolada que falhou. Se perder um evento,
reconcilie pela API usando o parâmetro
desde. - A URL precisa ser
https://. Dado pessoal não trafega em HTTP. - A ordem de chegada não é garantida. Use
atualizado_empara decidir qual versão é a mais recente. - Uma aprovação em lote dispara um evento por ficha, quase ao mesmo tempo. Um PDF de 34 páginas pode virar 34 chamadas seguidas — dimensione o seu endpoint.
Validar a assinatura
Calcule o HMAC-SHA256 do corpo bruto da requisição usando o segredo do
webhook e compare com o valor de x-assinatura. Três cuidados:
- Use o corpo exatamente como chegou, antes de qualquer parse de JSON. Serializar de novo muda os bytes e a assinatura não bate.
- Compare em tempo constante, nunca com
==. - Rejeite a requisição se a assinatura não bater. Não processe "só para conferir".
Node.js (Express)
const crypto = require('crypto');
// o corpo precisa chegar cru: express.raw, não express.json
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const esperado = 'sha256=' + crypto
.createHmac('sha256', process.env.WEBHOOK_SEGREDO)
.update(req.body)
.digest('hex');
const recebido = req.get('x-assinatura') || '';
const a = Buffer.from(esperado), b = Buffer.from(recebido);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).send('assinatura inválida');
}
const evento = JSON.parse(req.body.toString('utf8'));
res.sendStatus(200); // responda primeiro
processarEmSegundoPlano(evento); // trabalhe depois
});
Python (Flask)
import hmac, hashlib, os
from flask import request, abort
def valido(corpo: bytes, assinatura: str) -> bool:
esperado = 'sha256=' + hmac.new(
os.environ['WEBHOOK_SEGREDO'].encode(), corpo, hashlib.sha256
).hexdigest()
return hmac.compare_digest(esperado, assinatura)
@app.post('/webhook')
def webhook():
if not valido(request.get_data(), request.headers.get('x-assinatura', '')):
abort(401)
evento = request.get_json()
# enfileire aqui e devolva na hora
return '', 200
PHP
$corpo = file_get_contents('php://input');
$esperado = 'sha256=' . hash_hmac('sha256', $corpo, getenv('WEBHOOK_SEGREDO'));
$recebido = $_SERVER['HTTP_X_ASSINATURA'] ?? '';
if (!hash_equals($esperado, $recebido)) {
http_response_code(401);
exit;
}
$evento = json_decode($corpo, true);
http_response_code(200);
A aba API do sistema tem um botão Enviar teste que dispara uma
solicitacao.criada fictícia (com "teste": true no corpo) para a sua URL.
Use para validar a integração antes de entrar em produção — e ignore esse registro
no seu banco.
Erros e limites
Erros vêm sempre com este formato:
{ "erro": { "codigo": "nao_autenticado", "mensagem": "Token ausente ou inválido..." } }
| HTTP | Código | O que fazer |
|---|---|---|
| 401 | nao_autenticado | Token ausente, inválido ou revogado. Confira o cabeçalho Authorization: Bearer .... |
| 404 | nao_encontrado | O pedido não existe ou foi excluído. |
| 404 | rota_invalida | Caminho inexistente. Confira a grafia. |
| 405 | metodo_nao_permitido | A API é somente leitura: use GET. |
| 500 | erro_interno | Falha do servidor. Tente de novo com espera progressiva; se persistir, avise a administração. |
Boas práticas
- Não há limite de chamadas publicado, mas evite varrer a base inteira em ciclo curto.
Prefira webhook para saber de mudanças e use a consulta com
desdeapenas para reconciliar. - As respostas trazem
cache-control: no-store. Não guarde em cache compartilhado — são dados pessoais. - Guarde o
iddo pedido como chave estrangeira. Ele é estável e não muda. - Tokens são revogáveis a qualquer momento pela administração. Trate 401 como situação esperada, com alerta para o responsável, não como erro fatal silencioso.