Rootproof

Idioma

Tema

REST · v1

API Reference

Integrá Rootproof con tus sistemas para emitir, verificar y revocar certificados digitales atestados en blockchain.

Overview

Rootproof es una API REST para emitir, verificar y revocar certificados digitales atestados en blockchain (Rootstock / EAS).

  • Base URL: https://rootproof.io
  • Formato: JSON · UTF-8
  • Autenticación: Bearer token (API key) en header Authorization
  • Rate limits: 5 requests / minuto / IP en endpoints de emisión y revocación

Autenticación

Las integraciones programáticas usan API keys por organización. Genera una key desde Dashboard → Perfil → API Keys. La key plana se muestra una sola vez al crearla — guárdala en un gestor de secretos.

Authorization: Bearer rp_live_a1b2c3d4e5f6...

Las keys son por org y solo desbloquean el endpoint de emisión. Operaciones de configuración (firmas, plantilla, perfil, créditos) requieren login interactivo.

Emitir certificados

POST/api/org/{slug}/generateBearer · 5/min

Crea uno o muchos certificados (hasta 50 por request). Cada uno consume 1 crédito de la organización.

Body — un certificado:

{
  "certificateId": "CERT-2026-001",
  "recipientName": "María González",
  "programName": "Blockchain 101",
  "issuerName": "Universidad Rootproof",
  "issueDate": "2026-04-22",
  "recipientEmail": "maria@example.com",   // opcional, dispara email
  "recipientWallet": "0xAbc…",             // opcional, on-chain attestation target
  "validUntil": "2027-04-22",              // opcional
  "signatureIds": ["sig_uuid_1"]           // opcional, override de plantilla
}

Body — batch (array):

[
  { "certificateId": "CERT-001", "recipientName": "...", ... },
  { "certificateId": "CERT-002", "recipientName": "...", ... }
]

Respuesta 200:

{
  "ok": true,
  "creditsRemaining": 47,
  "results": [
    {
      "certificateId":   "CERT-2026-001",
      "status":          "OK",
      "verificationUrl": "https://rootproof.io/verify?id=CERT-2026-001",
      "pdfUrl":          "https://blob…/CERT-2026-001.pdf",
      "pdfHash":         "9F3A…",
      "attestationUID":  "0x4a7f…",
      "txHash":          "0xe1c…",
      "attestationUrl":  "https://explorer…",
      "explorerTxUrl":   "https://explorer…"
    }
  ]
}

Si status === "ERROR" en alguna fila, el resto del batch sigue procesándose y los créditos solo se descuentan por los exitosos.

Códigos de error:

  • 401 API key inválida o ausente
  • 402 Créditos insuficientes
  • 400 Batch > 50 o campos inválidos
  • 429 Rate limit excedido (header Retry-After)

Verificar certificados

GET/api/public/verify?id={certificateId}Public · 60/min

Devuelve el estado público de un certificado. CORS abierto.

{
  "verified": true,
  "type": "certificate",
  "id": "CERT-2026-001",
  "title": "Blockchain 101",
  "recipient": "María González",
  "issuer": "Universidad Rootproof",
  "certifiedDate": "2026-04-22",
  "verificationUrl": "https://rootproof.io/verify?id=CERT-2026-001",
  "revoked": false,
  "expired": false,
  "blockchain": {
    "network":         "rootstock",
    "attestationUID":  "0x…",
    "txHash":          "0x…",
    "attestationUrl":  "https://explorer…",
    "explorerTxUrl":   "https://explorer…"
  }
}

verified=false cuando el cert está revocado, vencido o no existe. Consultá revoked y expired para diferenciarlos.

GET/api/public/verify?hash={sha256_hex}Public · 60/min

Verificación por hash SHA-256 del PDF (64 caracteres hex). Útil para clientes que ya tienen el archivo localmente.

GET/api/public/issuer-info?name={issuer}Public · 60/min

Devuelve verified, profileUrl y logoUrl de un emisor. Útil para mostrar el badge "Verified Issuer" al lado del nombre.

GET/api/cert/{certificateId}/openbadgePublic · 60/min

Exporta el certificado como Open Badges 3.0 (IMS Global / 1EdTech) — formato estándar que ingieren LMS (Moodle, Canvas, Blackboard), credential wallets (Walt.id, ProofSpace, Learner Wallet), servicios de badges (Credly, Badgr/CanvasBadges) y validadores oficiales como imsglobal.org/badge-validator.

El JSON-LD respeta tanto W3C VC 2.0 como el contexto OB 3.0:

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json"
  ],
  "id":   "https://rootproof.io/api/cert/CERT-2026-001/openbadge",
  "type": ["VerifiableCredential", "OpenBadgeCredential"],
  "name": "Blockchain 101",
  "issuer": {
    "id":   "did:web:rootproof.io:org:acme",
    "type": ["Profile"],
    "name": "ACME University",
    "url":  "https://acme.example",
    "image": { "id": "https://...", "type": "Image" }
  },
  "validFrom":  "2026-04-22T00:00:00.000Z",
  "validUntil": "2027-04-22T23:59:59.999Z",
  "credentialSubject": {
    "type":       ["AchievementSubject"],
    "name":       "María González",
    "identifier": [
      { "type": "IdentityObject", "identityType": "emailAddress",
        "hashed": true, "identityHash": "sha256$…", "salt": "…" }
    ],
    "achievement": {
      "id":              "https://rootproof.io/cert/CERT-2026-001#achievement",
      "type":            ["Achievement"],
      "achievementType": "Certificate",
      "name":            "Blockchain 101",
      "description":     "...",
      "criteria":        { "narrative": "..." },
      "image":           { "id": "https://blob.../cert.pdf", "type": "Image" }
    }
  },
  "credentialStatus": {
    "id":   "https://rootproof.io/api/cert/CERT-2026-001/status",
    "type": "1EdTechRevocationList"
  },
  "evidence": [{
    "id":   "https://rootproof.io/verify?id=CERT-2026-001",
    "type": ["Evidence"],
    "name": "On-chain attestation",
    "narrative": "SHA-256(PDF) = ...\nAttestation UID = 0x..."
  }],
  "https://rootproof.io/ns#blockchainProof": {
    "blockchain":     "rootstock",
    "attestationUID": "0x…",
    "txHash":         "0x…",
    "verificationUrl":"https://rootproof.io/verify?id=CERT-2026-001"
  }
}

Por defecto sirve con Content-Disposition: attachment (descarga). Pasa ?format=inlinepara previsualizar en el browser. El email del destinatario nunca se expone en plano: se hashea con SHA-256 + salt aleatorio por credencial.

Revocar certificados

POST/api/org/{slug}/certificates/{certId}/revokeCookie · 5/min

Revoca un certificado on-chain (EAS) y off-chain (registro). Sólo desde el dashboard interactivo.

{ "reason": "Datos incorrectos en el certificado" }

Respuesta:

{
  "ok": true,
  "onChainRevoked": true,
  "certificate": { /* certificado completo con revokedAt */ }
}

Certificación de documentos

Además de certificados (con destinatario), Rootproof certifica documentos arbitrarios: subes el archivo, calculamos el hash SHA-256 y atestamos en blockchain. La verificación es por hash o por documentId.

POST/api/certify-docOTP · 5/min

Crea un documento certificado. Requiere verificación previa por OTP del email del propietario.

Flujo:

  1. Calcular SHA-256 del archivo en el cliente.
  2. POST /api/send-otp con { email }
  3. POST /api/verify-otp con { email, code } → recibe otpToken
  4. POST /api/certify-doc con el documento y el otpToken

Body:

{
  "ownerName":     "ACME Inc.",
  "ownerEmail":    "legal@acme.com",
  "ownerType":     "organization",            // "person" | "organization"
  "documentTitle": "Contrato de servicios 2026",
  "documentHash":  "9F3A4B…",                  // SHA-256 hex (64 chars)
  "fileSize":      48213,                      // opcional, bytes
  "otpToken":      "<token-de-verify-otp>"
}

Respuesta 200:

{
  "ok": true,
  "document": {
    "documentId":      "DOC-2026-001",
    "verificationUrl": "https://rootproof.io/doc/DOC-2026-001",
    "attestationUID":  "0x…",
    "txHash":          "0x…"
  }
}
GET/api/verify-doc?hash={sha256_hex}Public · 60/min

Verifica un documento por hash. CORS abierto.

{
  "found": true,
  "documentId":     "DOC-2026-001",
  "documentTitle":  "Contrato de servicios 2026",
  "ownerName":      "ACME Inc.",
  "ownerType":      "organization",
  "issueDate":      "2026-04-22",
  "attestationUID": "0x…",
  "txHash":         "0x…",
  "attestationUrl": "https://explorer…",
  "explorerTxUrl":  "https://explorer…"
}
GET/api/public/verify?hash={sha256_hex}Public · 60/min

Endpoint unificado: verifica certs y documentos por id o hash desde el mismo endpoint público.

GET/api/doc-pdf/{documentId}Public · 10/min

Descarga un PDF de comprobante con el hash y los datos on-chain del documento.

Por privacidad, el contenido del documento nunca se sube a Rootproof — solo el hash. Si perdés el original, no se puede reconstruir.

Webhooks

Configura una URL HTTPS en Dashboard → Perfil → Webhooks y la recibirás un POST por cada evento.

Eventos:

  • cert.issued — certificado emitido (UI o API)
  • cert.revoked — certificado revocado

Payload:

{
  "event": "cert.issued",
  "timestamp": "2026-04-22T12:34:56.789Z",
  "org": { "slug": "acme", "name": "ACME Inc." },
  "data": {
    "certificateId":   "CERT-2026-001",
    "recipientName":   "María González",
    "programName":     "Blockchain 101",
    "verificationUrl": "https://rootproof.io/verify?id=CERT-2026-001",
    "pdfUrl":          "https://blob…/CERT-2026-001.pdf",
    "attestationUID":  "0x…",
    "txHash":          "0x…",
    "pdfHash":         "9F3A…"
  }
}

Verificación de firma:

Si configuras un secreto (≥16 chars) recibes el header X-Rootproof-Signature:

X-Rootproof-Signature: t=1714000000000,v1=9f3a4b…
import crypto from "node:crypto";

function isValid(rawBody, signatureHeader, secret) {
  const [tPart, v1Part] = signatureHeader.split(",");
  const t  = tPart.split("=")[1];
  const v1 = v1Part.split("=")[1];

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(v1, "hex"),
    Buffer.from(expected, "hex")
  );
}

Timeout: 8s. Si tu endpoint falla, el evento se registra en el audit log con el código HTTP. No reintentamos automáticamente — usá cert.revoked + el endpoint público /api/public/verify para reconciliación si se pierde un evento.

Ejemplos

cURL — emisión simple:

curl -X POST https://rootproof.io/api/org/acme/generate \
  -H "Authorization: Bearer rp_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "certificateId": "CERT-2026-001",
    "recipientName": "María González",
    "programName": "Blockchain 101",
    "issuerName": "ACME University",
    "issueDate": "2026-04-22",
    "recipientEmail": "maria@example.com"
  }'

Node — batch:

const r = await fetch("https://rootproof.io/api/org/acme/generate", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.ROOTPROOF_KEY}`,
    "Content-Type":  "application/json",
  },
  body: JSON.stringify(students.map((s, i) => ({
    certificateId: `CERT-${i.toString().padStart(4, "0")}`,
    recipientName: s.name,
    recipientEmail: s.email,
    programName:   "Programa Anual 2026",
    issuerName:    "ACME University",
    issueDate:     "2026-12-15",
  }))),
});
const { ok, results, creditsRemaining } = await r.json();

Python — verificación:

import requests

r = requests.get("https://rootproof.io/api/public/verify",
                 params={"id": "CERT-2026-001"})
data = r.json()

if data["verified"]:
    print(f"OK: {data['recipient']} — {data['title']}")
else:
    if data.get("revoked"): print("Revocado")
    elif data.get("expired"): print("Vencido")
    else: print("No existe")