ProofKit

Documentación

API y especificación del recibo

Un endpoint y un documento JSON de respuesta. La respuesta es el recibo firmado.

POST /api/v1/check

Cuerpo: {"text": "…"} — UTF-8, de 5 a 20.000 caracteres. En el plan gratuito no hace falta clave.

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)."}'
EstadoSignificado
200Recibo: {body, sig, digest, log}
400Falta el texto, es demasiado corto o supera los 20.000 caracteres
429rate_limited (ráfaga) o monthly_limit — el plan gratuito es de 100 citas al mes por red

La cabecera de respuesta x-proofkit-remaining indica las citas gratuitas que quedan este mes. Los planes Pro y Team reciben una clave de API con límites más altos: envíela como Authorization: Bearer pk_live_… y la respuesta incluirá x-proofkit-plan. Una clave no válida devuelve 401 invalid_api_key; un plan caducado pasa al plan gratuito.

Campos del recibo

CampoDescripción
body.specsapir-receipt/1
body.kindcitation-check
body.tsHora UTC de la comprobación, ISO-8601
body.input_sha256SHA-256 del texto exacto de entrada (demuestra qué texto se comprobó sin guardarlo)
body.checkerMétodo y fuente utilizados
body.results[]jurisdiction (US|UK|EU|ECHR), cite, name, verdict, note, source, opinion, matched_case
verdictverified · mismatch (cita real, otro caso) · not_found · ambiguous · exists_name_unchecked · unverifiable · unchecked
body.summarytotal, verified, flagged
body.keyClave pública de firma (Ed25519, JWK x)
sigFirma Ed25519 (base64url) sobre el JSON canónico de body
digestSHA-256 en hex del JSON canónico de body
logPosición n y hash de la cadena en el registro público de transparencia

JSON canónico: claves de los objetos ordenadas, sin espacios, escape estándar de cadenas JSON y se omiten los campos undefined.

Verificación

  1. Serialice body de forma canónica.
  2. El SHA-256 debe coincidir con digest.
  3. Verifique sig con Ed25519 sobre los mismos bytes con la clave de /.well-known/proofkit-pubkey; debe coincidir con body.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");

Límites. Léalos antes de confiar en el resultado

  • Cobertura: EE. UU. — CourtListener (en funcionamiento; algunos repertorios estatales y antiguos están incompletos). Reino Unido — Find Case Law (beta; fiable desde 2022). UE — EUR-Lex, Tribunal de Justicia y Tribunal General (beta). TEDH — HUDOC (beta). Cada resultado tiene un campo jurisdiction.
  • Las citas de Westlaw (WL), Lexis y de dominio público no se pueden contrastar con una base abierta, así que se marcan como unverifiable.
  • La coincidencia de nombres se basa en palabras (≥ 0,5). Nombres de caso muy cortos o poco habituales pueden dar mismatch en un caso real. Abra siempre el enlace a la fuente.
  • Verificamos la existencia y la identidad del caso, no si respalda el argumento.