Documentação
API e especificação do recibo
Um endpoint, um documento JSON de volta. A resposta é o recibo assinado.
POST /api/v1/check
Corpo: {"text": "…"} — UTF-8, de 5 a 20.000 caracteres. No plano gratuito não é preciso chave.
curl -X POST https://proof.sapir861.com/api/v1/check \
-H "content-type: application/json" \
-d '{"text":"See Marbury v. Madison, 5 U.S. 137 (1803)."}'| Estado | Significado |
|---|---|
| 200 | Recibo: {body, sig, digest, log} |
| 400 | Texto em falta, demasiado curto ou com mais de 20.000 caracteres |
| 429 | rate_limited (pico) ou monthly_limit — o plano gratuito tem 100 citações por mês por rede |
O cabeçalho de resposta x-proofkit-remaining mostra as citações gratuitas que restam este mês. Os planos Pro e Team recebem uma chave de API com limites maiores: envie-a como Authorization: Bearer pk_live_… e a resposta trará x-proofkit-plan. Uma chave inválida devolve 401 invalid_api_key; um plano expirado passa para o plano gratuito.
Campos do recibo
| Campo | Descrição |
|---|---|
body.spec | sapir-receipt/1 |
body.kind | citation-check |
body.ts | Hora UTC da verificação, ISO-8601 |
body.input_sha256 | SHA-256 do texto exato de entrada (prova que texto foi verificado sem o guardar) |
body.checker | Método e fonte usados |
body.results[] | jurisdiction (US|UK|EU|ECHR), cite, name, verdict, note, source, opinion, matched_case |
verdict | verified · mismatch (citação real, outro caso) · not_found · ambiguous · exists_name_unchecked · unverifiable · unchecked |
body.summary | total, verified, flagged |
body.key | Chave pública de assinatura (Ed25519, JWK x) |
sig | Assinatura Ed25519 (base64url) sobre o JSON canónico de body |
digest | SHA-256 em hex do JSON canónico de body |
log | Posição n e hash da cadeia no registro público de transparência |
JSON canónico: chaves dos objetos ordenadas, sem espaços, escape padrão de strings JSON e campos undefined omitidos.
Verificação
- Serialize
bodyde forma canónica. - O SHA-256 tem de ser igual a
digest. - Verifique
sigcom Ed25519 sobre os mesmos bytes com a chave de /.well-known/proofkit-pubkey; tem de ser igual abody.key.x.
import { readFileSync } from "node:fs"; // node verify.mjs receipt.json (Node 20+)
const r = JSON.parse(readFileSync(process.argv[2] || "receipt.json", "utf8"));
const canon = o => o === null || typeof o !== "object" ? JSON.stringify(o) : Array.isArray(o) ? "[" + o.map(canon).join(",") + "]"
: "{" + Object.keys(o).sort().filter(k => o[k] !== undefined).map(k => JSON.stringify(k) + ":" + canon(o[k])).join(",") + "}";
const msg = new TextEncoder().encode(canon(r.body));
const hex = Buffer.from(await crypto.subtle.digest("SHA-256", msg)).toString("hex");
const pub = (await (await fetch("https://proof.sapir861.com/.well-known/proofkit-pubkey")).json()).jwk;
const key = await crypto.subtle.importKey("jwk", pub, { name: "Ed25519" }, false, ["verify"]);
const ok = await crypto.subtle.verify({ name: "Ed25519" }, key, Buffer.from(r.sig, "base64url"), msg);
console.log(ok && hex === r.digest && pub.x === r.body.key.x ? "VALID" : "INVALID");# pip install cryptography ; python verify.py receipt.json
import json, sys, base64, hashlib, urllib.request
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
r = json.load(open(sys.argv[1] if len(sys.argv) > 1 else "receipt.json", encoding="utf-8"))
b64 = lambda s: base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
msg = json.dumps(r["body"], sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode()
pub = json.load(urllib.request.urlopen("https://proof.sapir861.com/.well-known/proofkit-pubkey"))["jwk"]
try:
Ed25519PublicKey.from_public_bytes(b64(pub["x"])).verify(b64(r["sig"]), msg)
ok = hashlib.sha256(msg).hexdigest() == r["digest"] and pub["x"] == r["body"]["key"]["x"]
except Exception: ok = False
print("VALID" if ok else "INVALID")Sem instalar nada: abra https://proof.sapir861.com/pt/verify e cole o receipt.json.
A verificação corre localmente no navegador (WebCrypto Ed25519). Nada é enviado.Limites. Leia antes de confiar no resultado
- Cobertura: EUA — CourtListener (a funcionar; alguns repertórios estaduais e antigos estão incompletos). Reino Unido — Find Case Law (beta; fiável desde 2022). UE — EUR-Lex, Tribunal de Justiça e Tribunal Geral (beta). TEDH — HUDOC (beta). Cada resultado tem um campo jurisdiction.
- As citações Westlaw (WL), Lexis e de domínio público não podem ser verificadas numa base aberta, por isso são marcadas como
unverifiable. - A comparação de nomes é feita por palavras (≥ 0,5). Nomes de caso muito curtos ou invulgares podem dar
mismatchnum caso real. Abra sempre a ligação para a fonte. - Verificamos a existência e a identidade do caso, não se ele apoia o argumento.