Volver al blog

API de sello de tiempo: cómo certificar documentos desde tu aplicación

Respuesta JSON de la API de sello de tiempo de Sellat con el anclaje en Polygon y el sello cualificado de la FNMT

Una API de sello de tiempo hace una sola cosa: toma la huella SHA-256 de un archivo y la fija en una fecha que nadie puede mover, para que dentro de dos años puedas demostrar que ese archivo exacto ya existía. La API v2 de Sellat lo resuelve en una llamada HTTP: envías el hash (nunca el archivo) y recibes un registro anclado en Polygon y Bitcoin y, si lo pides, un sello de tiempo cualificado emitido por la FNMT-RCM. La prueba se descarga como JSON y se verifica sin Sellat, con un verificador de código abierto o con OpenSSL.

Esta guía es para quien quiere sellar desde su propio sistema, no desde una web: un SaaS que necesita demostrar cuándo aceptó algo un usuario, un despacho que automatiza expedientes, una tienda que guarda la versión de sus condiciones en cada pedido, un sistema que firma sus logs cada noche o una agencia que sella cada entrega antes de enviarla. Verás qué devuelve la API, cómo se integra en tres llamadas, cómo se verifica sin nosotros y, sobre todo, qué demuestra y qué no.

Qué devuelve la API: la prueba, capa a capa

Lo único que sale de tu servidor es el hash SHA-256 del archivo, 64 caracteres hexadecimales. Con él, Sellat construye una prueba de existencia en capas independientes, cada una con su propia fecha y su propia autoridad:

  1. Lote Merkle y anclaje en Polygon. El hash entra en un lote (como máximo dos minutos de espera), se calcula la raíz Merkle del lote y esa raíz se escribe en un contrato en Polygon Mainnet (chain_id 137). La prueba guarda el camino Merkle y la transacción (tx_hash, block_number), que cualquiera puede consultar en un explorador público.
  2. Atestación en Bitcoin. La misma raíz se envía a OpenTimestamps; el campo bitcoin pasa de pending a confirmed con su block_height cuando entra en un bloque, normalmente en horas.
  3. Sello de tiempo cualificado (opcional). Si envías "qualified": true, la FNMT-RCM emite un sello RFC 3161 sobre el hash. Se emite al instante e independientemente del anclaje, y se descarga como .tsr en formato DER. Es la capa con presunción legal en la UE; la emite la FNMT, no Sellat.
  4. La prueba portable. GET /proof/{id}.json es el único endpoint público: devuelve el JSON con esquema sellat-proof/2 (hash, hoja, camino Merkle, anclajes y atestaciones), sin autenticación. Es lo que entregas a un tercero.
  5. Certificado y paquete de evidencias. Un PDF en es, en, de o fr con hash, fechas, anclajes y sello, y un evidence.zip con el certificado, el proof.json, el .tsr, el certificado de la autoridad y las instrucciones de verificación. Si has depositado el original en custodia, también va dentro.

El estado de la prueba avanza solo; no hay que hacer nada entre llamadas:

EstadoQué significa
queuedRecibida; esperando lote (máximo 2 minutos)
batchedEn un lote Merkle con camino fijo; esperando el anclaje en Polygon
anchoredAnclada en un bloque de Polygon; proof.json ya disponible
confirmedEl bloque tiene 12 confirmaciones

El sello cualificado y la atestación en Bitcoin tienen sus propios campos (qualified.state, bitcoin.state) y no dependen de esta secuencia.

Tu primer sello en tres llamadas

Necesitas una clave de API, que se crea y se revoca desde el panel (hasta cinco activas por cuenta), y se envía como Authorization: Bearer sellat_.... La API no envía cabeceras CORS: se llama desde tu servidor, nunca desde código en el navegador, y la clave no sale de ahí.

1. Calcula el hash y crea la prueba. El archivo no se envía. La cabecera Idempotency-Key hace que un reintento devuelva la misma prueba ("created": false) sin consumir otro sello.

export SELLAT_API_TOKEN=sellat_...
HASH=$(sha256sum contrato.pdf | cut -d' ' -f1)

curl https://sellat.app/api/v2/proofs \
  -H "Authorization: Bearer $SELLAT_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: expediente-2026-0142" \
  -d "{\"hash\":\"$HASH\",\"name\":\"contrato.pdf\",\"qualified\":true,\"metadata\":{\"ref\":\"expediente-2026-0142\"}}

La respuesta (201) trae el id, el estado inicial queued, el bloque qualified ya en issued con la autoridad FNMT-RCM, la hora del sello y la URL del .tsr, y las URLs de descarga. Si la cuenta no tiene sellos, la respuesta es 402 payment_required con seals_remaining y buy_url; puedes crear la prueba sin qualified y pedir el sello más tarde con POST /proofs/{id}/qualified.

2. Consulta el estado hasta que esté anclada. En unos minutos pasa a anchored; no hace falta consultar más de una vez por minuto.

curl https://sellat.app/api/v2/proofs/{id} \
  -H "Authorization: Bearer $SELLAT_API_TOKEN"

3. Descarga el paquete y guárdalo con el archivo. El ZIP contiene todo lo necesario para verificar sin Sellat.

curl -L "https://sellat.app/api/v2/proofs/{id}/evidence.zip?lang=es" \
  -H "Authorization: Bearer $SELLAT_API_TOKEN" -o evidencias.zip

Si además quieres que Sellat custodie el original, PUT /proofs/{id}/original con el archivo en el cuerpo (10 MB por archivo en el plan gratuito, 50 MB en Pro); el servicio recalcula el hash y rechaza el depósito si no coincide (409 hash_mismatch). Los metadata que envíes se guardan en privado y no se publican en ningún sitio. Hay un cliente de terminal, sellat-cli, que empaqueta estas tres llamadas para sellar logs o carpetas desde un cron, y la especificación completa está en OpenAPI.

Verificar sin Sellat

Una prueba que solo pueda comprobar quien la emitió no es una prueba. Por eso el formato es público, el verificador es de código abierto y el sello cualificado se valida con herramientas estándar. Dos comandos:

# Anclaje: recalcula el hash, recorre el camino Merkle y lee el bloque de Polygon
curl https://sellat.app/api/v2/proof/{id}.json -o proof.json
npx sellat-verify contrato.pdf proof.json

# Sello cualificado: OpenSSL, con el certificado de la autoridad que va en el ZIP
openssl ts -verify -in sello.tsr -data contrato.pdf \
  -CAfile autoridad-sellado.pem -partial_chain

El primero comprueba que el hash del archivo que tienes delante es el que está en la raíz anclada en Polygon; el segundo, que la FNMT-RCM firmó ese mismo hash a la hora que indica el sello y que el certificado está en la lista de confianza de la UE. Si prefieres no tocar la terminal, el validador de sellos de tiempo hace las siete comprobaciones en el navegador, sin subir el archivo, y acepta sellos de cualquier autoridad, no solo los de Sellat. El código está en sellat-verify, junto con la especificación del formato sellat-proof/2.

Qué demuestra y qué no

Demuestra dos cosas: que un archivo con exactamente ese hash existía en el momento del anclaje y del sello, y que el archivo que presentas hoy no ha cambiado ni un byte desde entonces. No demuestra quién lo creó, ni que su contenido sea cierto, ni que la otra parte lo recibiera. Para eso hay otras herramientas (firma electrónica, correo certificado, un perito), y un buen expediente suele combinar varias.

Sobre el marco legal, con precisión: el sello de tiempo cualificado lo emite la FNMT-RCM, un prestador cualificado de la lista de confianza de la UE; Sellat no es prestador cualificado y no emite sellos, los solicita y los entrega. Ese sello cualificado disfruta de la presunción del artículo 41.2 del Reglamento eIDAS: se presume la exactitud de la fecha y la integridad de los datos a los que va unido, y quien lo discuta tiene que probar lo contrario. El anclaje en Polygon y Bitcoin no tiene esa presunción; es una prueba técnica que un perito puede reproducir sin confiar en nadie y que sigue siendo verificable aunque Sellat o la FNMT desaparecieran.

Por eso la prueba muestra siempre dos fechas separadas: la del anclaje y la del sello cualificado. Pedir el sello más tarde no retrotrae nada: el sello lleva la hora en que la FNMT lo emitió, no la del anclaje. Y si el mismo hash ya lo había registrado otra cuenta antes, la prueba se crea igual y es válida, pero llega con "limitations": ["hash_registered_by_another_account"] y sin certificado exclusivo: la API no oculta que alguien llegó primero.

Precio, límites y cuándo usar la API

Empezar no cuesta nada: el plan gratuito permite 10 pruebas al día por cuenta (se reinicia a las 00:00 UTC), incluye un sello cualificado de bienvenida y 50 MB de custodia. El anclaje en Polygon y Bitcoin no se cobra por prueba; lo que se paga es el sello cualificado, a 6 € la unidad o menos en packs, y el plan Pro, que sube el límite a 5.000 pruebas al día y la custodia a 5 GB. Los precios vigentes están en sellat.app/precios; GET /account te devuelve en todo momento sellos restantes, cuota usada y espacio de custodia, para que tu sistema sepa cuándo avisar.

Dos límites que conviene conocer antes de diseñar la integración: 60 creaciones de prueba por minuto y 10 peticiones de sello por minuto por clave (la API responde 429 con Retry-After), y una única petición de sello cualificado por prueba. Todavía no hay endpoints por lotes ni webhooks de cambio de estado: para sellar muchos archivos, un hash por llamada; para saber cuándo una prueba pasa a anchored, consulta GET /proofs/{id} con un intervalo razonable.

¿API, plugin o web? La web (sellat.app/protect) sirve para sellar a mano, archivo a archivo. El plugin para WooCommerce (sale en pocos días) resuelve un caso concreto sin programar: guardar qué condiciones mostraba la tienda en cada pedido. La API es para todo lo demás: cuando el sello tiene que ocurrir dentro de un flujo que ya existe, sin que nadie pulse un botón.

Preguntas frecuentes

¿Tengo que enviar el archivo a Sellat? No. La API solo recibe el hash SHA-256, que no permite reconstruir el contenido. El archivo se queda en tu servidor; solo sale de él si tú decides depositarlo en custodia con PUT /proofs/{id}/original.

¿Cuánto tarda en estar lista la prueba? El sello cualificado se emite al instante. El anclaje en Polygon tarda unos minutos (lote de hasta dos minutos más la inclusión en bloque) y pasa a confirmed con 12 confirmaciones. La atestación en Bitcoin suele confirmarse en horas. Puedes descargar el certificado en cuanto el estado es anchored.

¿Sirve como prueba en un juicio? Una prueba electrónica no se rechaza solo por serlo. El sello cualificado tiene presunción de exactitud e integridad en toda la UE (art. 41.2 eIDAS) y el anclaje es reproducible por un perito. Lo que no hace ninguna de las dos capas es acreditar autoría o veracidad del contenido: eso lo aportan otras pruebas del expediente.

¿Qué pasa si registro dos veces el mismo archivo? Si es tu cuenta, la API devuelve la prueba existente (200, "created": false) sin consumir sellos. Si otra cuenta registró antes ese hash, se crea una prueba nueva, válida y anclada, marcada con limitations y sin certificado exclusivo.

¿Tienes un archivo que proteger?

Sellat crea una prueba verificable de la versión exacta de tu archivo en el momento en que la proteges.

Proteger archivos