API de Autógrafos

Consulta e webhooks para integração com outros sistemas — v1

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

GET/v1/solicitacoes lista pedidos, com filtros e paginação
GET/v1/solicitacoes/{id} um pedido específico
GET/v1/estatisticas totais por livro, situação e evento

Parâmetros de /v1/solicitacoes

ParâmetroTipoDescrição
qtextoBusca livre no nome da dedicatória, no comprador, e-mail, telefone, título do livro e evento. Ignora acentos: q=jose encontra "José".
livroenumChave do livro. Só traz pedidos que incluam esse título. Lista completa em Modelo de dados.
statusenumpendente, assinado, entregue, cancelado
eventotextoFiltra pelo evento de origem (busca parcial).
desdedata ISOSó pedidos criados a partir desta data. Ex.: 2026-08-01
limiteinteiroItens por página. Padrão 50, máximo 200.
offsetinteiroQuantos 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

ValorSignificado
pendenteConferido pelo gabinete, aguardando a assinatura do senador.
assinadoLivro assinado, aguardando entrega ou envio.
entregueEntregue a quem pediu. Ciclo encerrado.
canceladoPedido 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

EventoQuando dispara
solicitacao.criadaUma ficha foi conferida e virou pedido definitivo.
solicitacao.atualizadaAlgum campo de um pedido existente mudou — inclusive a passagem para assinado ou entregue.
solicitacao.excluidaUm 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çalhoConteúdo
x-eventoNome do evento, ex.: solicitacao.criada
x-entrega-idUUID único desta entrega. Use para descartar duplicatas.
x-assinaturasha256=<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

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:

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..." } }
HTTPCódigoO que fazer
401nao_autenticadoToken ausente, inválido ou revogado. Confira o cabeçalho Authorization: Bearer ....
404nao_encontradoO pedido não existe ou foi excluído.
404rota_invalidaCaminho inexistente. Confira a grafia.
405metodo_nao_permitidoA API é somente leitura: use GET.
500erro_internoFalha do servidor. Tente de novo com espera progressiva; se persistir, avise a administração.

Boas práticas