Referencia de la API
API v2 de Sellat
Todo lo que hace la web, desde tu sistema: registrar la huella SHA-256 de un archivo, anclarla en Polygon y Bitcoin, pedir el sello de tiempo cualificado de la FNMT, descargar el certificado y el paquete de evidencias, y custodiar el original. REST y JSON, con una clave de API.
https://sellat.app/api/v2 Introducción
La API trabaja con la huella del archivo, no con el archivo: calculas el SHA-256 en tu sistema y envías solo esos 64 caracteres. El original no sale de tu máquina salvo que decidas dejarlo en custodia.
Cada prueba entra en un lote Merkle anclado en Polygon, y el mismo lote se atesta en Bitcoin. Si lo pides, la huella recibe además el sello de tiempo cualificado de la FNMT-RCM, prestador cualificado de la lista de confianza de la UE.
Todas las rutas cuelgan de la URL base y hablan JSON. Las pruebas que creas por API y las que creas en la web son de la misma cuenta y aparecen en el mismo panel.
Está pensada para llamarse desde un servidor: no envía cabeceras CORS, así que un navegador no puede llamarla desde otra web, y tu clave nunca debe estar en código que llegue al navegador.
Autenticación
Cada petición lleva tu clave en la cabecera Authorization: Bearer sellat_.... Las claves se crean y se revocan desde tu panel; una cuenta puede tener hasta 5 activas, una por integración.
Sin clave, o con una clave revocada, la API responde 401 unauthorized con la cabecera WWW-Authenticate: Bearer. La única ruta pública es la prueba portable (/proof/{id}.json).
curl https://sellat.app/api/v2/account \
-H "Authorization: Bearer sellat_3f9c..." Inicio rápido
Calcula la huella, crea la prueba con el sello cualificado y guarda el id que te devuelve. En pocos minutos pasa a anchored y todas sus URLs funcionan.
Sin "qualified": true la prueba es igual de verificable (Polygon y Bitcoin) y no gasta un sello. Puedes pedir el sello más tarde con POST /proofs/{id}/qualified.
# Your key, from the dashboard
export SELLAT_API_TOKEN=sellat_...
# The fingerprint: the file stays on your machine
HASH=$(sha256sum contract.pdf | cut -d' ' -f1)
# The proof, with the FNMT qualified seal
curl https://sellat.app/api/v2/proofs \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"hash\":\"$HASH\",\"name\":\"contract.pdf\",\"qualified\":true}" Estados de una prueba
El campo state dice lo que Sellat sabe en cada momento: nunca marca como confirmada una transacción que todavía no ha comprobado.
El atestado en Bitcoin (bitcoin) va aparte: pending hasta que OpenTimestamps lo incluye en un bloque, y entonces confirmed con su altura. El sello cualificado (qualified) no depende del estado: se emite al momento.
| Estado | Qué significa |
|---|---|
queued | Recibida. Espera a entrar en un lote, como mucho unos dos minutos. |
batched | En un lote Merkle, con su ruta fijada. Espera el anclaje en Polygon. |
anchored | Anclada: la transacción está en un bloque de Polygon. Ya hay proof.json. |
confirmed | El bloque tiene 12 confirmaciones. |
Errores
Un error es siempre un JSON con error.code (estable, para tu código) y error.message (para personas). Algunos añaden campos, como seals_remaining y buy_url en un 402. La prueba portable, que es pública, responde {"error": "..."}.
Si la puerta de enlace corta antes de llegar a la API (demasiadas peticiones por IP, o un cuerpo de más de 25 MB), ese 429 o ese 413 no llevan este formato.
| Código | HTTP | Qué pasa |
|---|---|---|
invalid_request | 400 | Falta un campo o no tiene el formato esperado. El mensaje dice cuál. |
unauthorized | 401 | Sin clave, clave mal formada o revocada. |
payment_required | 402 | No te quedan sellos cualificados. Trae seals_remaining y buy_url. |
key_without_account | 403 | La clave no pertenece a una cuenta (claves antiguas). |
not_found | 404 | La prueba no existe o es de otra cuenta. |
conflict | 409 | Esos bytes los registró primero otra cuenta, o el original todavía no está guardado. |
hash_mismatch | 409 | El archivo que subes no tiene la huella de la prueba. |
file_too_large | 413 | El archivo supera el límite por archivo de tu plan (max_file_bytes). |
rate_limited | 429 | Demasiadas peticiones por minuto. Respeta Retry-After. |
quota_exceeded | 429 | Has llegado al límite diario de pruebas. Retry-After hasta las 00:00 UTC. |
download_quota_exceeded | 429 | Has llegado al límite diario de descargas del original. |
integrity_failed | 500 | El original guardado ya no coincide con su huella, así que no se entrega. |
unavailable | 502 · 503 | Un servicio interno no responde. Reintenta más tarde. |
seal_unavailable | 503 | La autoridad de sellado no está disponible ahora. |
custody_unavailable | 503 | La custodia no está disponible en este momento. |
custody_quota_exceeded | 507 | No queda espacio de custodia en tu cuenta. |
{
"error": {
"code": "payment_required",
"message": "No qualified seals left on this account.",
"seals_remaining": 0,
"buy_url": "https://sellat.app/precios"
}
} Límites
Cada cuenta puede crear un número de pruebas por API al día, sumando todas sus claves. Las pruebas que haces desde la web no cuentan, y volver a enviar bytes que ya son tuyos tampoco. El día se reinicia a las 00:00 UTC.
Al llegar al límite, POST /proofs responde 429 quota_exceeded con el objeto quota y Retry-After. Además, cada ruta tiene un freno por minuto (por ejemplo, 60 creaciones y 10 sellos por minuto) que responde 429 rate_limited, y la puerta de enlace admite hasta 120 peticiones por minuto por IP. Un cuerpo puede ocupar como mucho 25 MB.
Los sellos cualificados no tienen límite diario: cada uno gasta un sello de tu saldo. Consulta en cualquier momento lo que te queda con GET /account, y si necesitas más volumen, escríbenos a [email protected].
| Cuenta gratuita | Cuenta Pro | |
|---|---|---|
| Pruebas por API al día | 10 | 5000 |
| Claves activas | 5 | 5 |
| Original en custodia, por archivo | 10 MB | 50 MB |
| Custodia total | 50 MB | 5 GB |
| Descargas del original al día | 10 | 50 |
HTTP/1.1 429 Too Many Requests
Retry-After: 41231
{
"error": {
"code": "quota_exceeded",
"message": "Daily limit reached: 10 proofs per account per UTC day across all its keys.",
"quota": {
"limit": 10,
"used": 10,
"resets_in_seconds": 41231
}
}
} Idempotencia
Envía la cabecera Idempotency-Key (hasta 200 caracteres) en POST /proofs y podrás reintentar sin miedo: si ya la usaste con esa misma clave de API, recibes la prueba original con 200 y "created": false, diga lo que diga el cuerpo nuevo, y no se emite ningún sello.
Sin la cabecera, enviar otra vez unos bytes que ya son de tu cuenta también devuelve la prueba que existe (200), sin cambiar su nombre ni sus metadatos. Pero si esos bytes los registró primero otra cuenta, cada envío crea una prueba nueva con limitations: si puedes reintentar, usa siempre Idempotency-Key.
El sello tampoco se duplica: una prueba tiene un solo sello, y pedirlo otra vez devuelve el mismo sin gastar otro.
Verificar sin Sellat
Una prueba de Sellat no necesita a Sellat para comprobarse. Con el archivo y su proof.json, el verificador de código abierto recalcula la huella y la ruta Merkle, y lee el anclaje en la blockchain pública.
El sello cualificado se comprueba con OpenSSL, con el archivo, el .tsr y el certificado de la autoridad, que viene dentro del paquete de evidencias. -partial_chain hace falta porque la lista de confianza publica el certificado de la propia autoridad, no el de una CA.
# 1. The proof: file + proof.json + the public blockchain
curl https://sellat.app/api/v2/proof/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e.json -o proof.json
npx sellat-verify contract.pdf proof.json
# 2. The qualified seal: file + .tsr + the authority's certificate
# (autoridad-sellado.pem comes inside evidence.zip)
openssl ts -verify -in seal.tsr -data contract.pdf \
-CAfile autoridad-sellado.pem -partial_chain Pruebas
Crear una prueba
POST /proofs
Registra la huella SHA-256 de un archivo y devuelve la prueba. Con "qualified": true emite además, en la misma llamada, el sello cualificado de la FNMT, y gasta un sello de la cuenta.
Parámetros
-
hashobligatorio - La huella SHA-256 del archivo: 64 caracteres hexadecimales.
-
nameopcional - Cómo se llamará en el panel y en el certificado. Se guarda solo el nombre, sin la ruta. Por defecto, los 12 primeros caracteres de la huella.
-
metadataopcional - Un objeto JSON tuyo, de hasta 4 KB. Se guarda con la prueba y no se devuelve ni se publica nunca.
-
sizeopcional - Tamaño del archivo en bytes. Informativo.
-
mime_typeopcional - Tipo del archivo. Se usa al servir el original si lo custodias. Por defecto,
application/octet-stream. -
qualifiedopcional -
trueemite también el sello cualificado de la FNMT. -
Idempotency-Keyopcional - Para reintentar sin duplicar (ver Idempotencia).
Respuestas
- 201
- Prueba creada.
- 200
- Ya existía: esos bytes ya son de tu cuenta, o repetiste una
Idempotency-Key. Trae"created": false. - 400
invalid_request: un campo falta o no es válido.- 401
unauthorized.- 402
payment_required: pediste el sello y no te quedan. No se escribe nada.- 409
conflict: pediste el sello sobre bytes que registró primero otra cuenta.- 429
quota_exceeded(límite diario) orate_limited(por minuto).- 503
seal_unavailableounavailable. Si la prueba llegó a crearse, el error trae suproof_id.
Si la autoridad tarda en responder, la prueba se crea igual y qualified llega como {"state": "pending"}: pídelo otra vez con POST /proofs/{id}/qualified, sin coste.
Si esos bytes los registró primero otra cuenta, la prueba se crea y se ancla, pero sin certificado propio: las URLs del certificado son null y la respuesta trae "limitations": ["hash_registered_by_another_account"].
curl https://sellat.app/api/v2/proofs \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: contract-2026-0142" \
-d '{
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f",
"name": "contract.pdf",
"qualified": true,
"metadata": { "ref": "case-2026-0142" }
}' {
"id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"created": true,
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f",
"algorithm": "SHA-256",
"name": "contract.pdf",
"state": "queued",
"received_at": "2026-09-30T09:12:03.418Z",
"anchors": [],
"bitcoin": {
"state": "pending",
"block_height": null
},
"qualified": {
"state": "issued",
"authority": "FNMT-RCM",
"time": "2026-09-30T09:12:05.000Z",
"serial_number": "175755C77B4239226AA0428FE1C107C1",
"policy_oid": "0.4.0.2023.1.1",
"tsr_url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr"
},
"original": null,
"urls": {
"self": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"proof_json": "https://sellat.app/api/v2/proof/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e.json",
"certificate": "https://sellat.app/certificate/3b1d7e42-9c5a-4f0e-b8d6-1a2c3e4f5a6b",
"certificate_pdf": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/certificate.pdf",
"evidence_zip": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/evidence.zip"
}
} Consultar una prueba
GET /proofs/{id}
Devuelve la prueba con su estado, sus anclajes, el atestado en Bitcoin, el sello si lo tiene, el original si está en custodia y todas sus URLs.
Parámetros
-
idobligatorio - El
idde la prueba.
Respuestas
- 200
- La prueba.
- 401
unauthorized.- 404
not_found: no existe o es de otra cuenta.
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f",
"algorithm": "SHA-256",
"name": "contract.pdf",
"state": "anchored",
"received_at": "2026-09-30T09:12:03.418Z",
"anchors": [
{
"network": "Polygon Mainnet",
"chain_id": 137,
"state": "anchored",
"tx_hash": "0xa4195d4ea808610dee92a1caa221d35f289e61674f451c82f7428e29813f9d6a",
"block_number": 94653624,
"block_timestamp": "2026-09-30T09:14:36.000Z",
"explorer_url": "https://polygonscan.com/tx/0xa4195d4ea808610dee92a1caa221d35f289e61674f451c82f7428e29813f9d6a"
}
],
"bitcoin": {
"state": "pending",
"block_height": null
},
"qualified": {
"state": "issued",
"authority": "FNMT-RCM",
"time": "2026-09-30T09:12:05.000Z",
"serial_number": "175755C77B4239226AA0428FE1C107C1",
"policy_oid": "0.4.0.2023.1.1",
"tsr_url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr"
},
"original": null,
"urls": {
"self": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"proof_json": "https://sellat.app/api/v2/proof/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e.json",
"certificate": "https://sellat.app/certificate/3b1d7e42-9c5a-4f0e-b8d6-1a2c3e4f5a6b",
"certificate_pdf": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/certificate.pdf",
"evidence_zip": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/evidence.zip"
}
} Listar pruebas
GET /proofs
Las pruebas de tu cuenta, de la más reciente a la más antigua: las creadas por API y las creadas en la web. Cada elemento de data es una prueba completa, como la de GET /proofs/{id}.
Para la página siguiente, pasa el next_cursor que te devolvió la anterior. Cuando es null, no hay más.
Parámetros
-
limitopcional - Cuántas pruebas por página, de 1 a 100. Por defecto, 25.
-
cursoropcional - El
next_cursorde la página anterior.
Respuestas
- 200
dataynext_cursor.- 400
invalid_request:limitocursorno válidos.- 401
unauthorized.
curl "https://sellat.app/api/v2/proofs?limit=25" \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"data": [
{
"id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f",
"name": "contract.pdf",
"state": "confirmed",
"received_at": "2026-09-30T09:12:03.418Z"
}
],
"next_cursor": "1843"
} Sello cualificado (eIDAS)
Pedir el sello cualificado
POST /proofs/{id}/qualified
Emite un sello de tiempo RFC 3161 de la FNMT-RCM sobre la huella del archivo. Según el art. 41.2 del Reglamento eIDAS, un sello de tiempo cualificado goza de la presunción de exactitud de su fecha y hora y de integridad de los datos.
Gasta un sello de la cuenta: el de bienvenida o uno de tus packs. La API nunca cobra una tarjeta ni abre un pago; los packs se compran en la página de precios.
Parámetros
-
idobligatorio - El
idde la prueba.
Respuestas
- 200
- Sello emitido, o ya lo tenía (
"created": false, sin gastar otro). Traeseals_remaining. - 202
- El sello se ha pagado, pero la autoridad no ha respondido. Llama otra vez (
Retry-After: 30): se completa sin coste. - 401
unauthorized.- 402
payment_required: no te quedan sellos. Traeseals_remainingybuy_url.- 404
not_found.- 409
conflict: esos bytes los registró primero otra cuenta.- 503
seal_unavailable.
Una prueba tiene un solo sello, para siempre. Si la emisión falla del todo, el sello vuelve a tu saldo.
curl -X POST https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"proof_id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"created": true,
"qualified": {
"state": "issued",
"authority": "FNMT-RCM",
"time": "2026-09-30T09:12:05.000Z",
"serial_number": "175755C77B4239226AA0428FE1C107C1",
"policy_oid": "0.4.0.2023.1.1",
"tsr_url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr"
},
"seals_remaining": 4
} Consultar el sello
GET /proofs/{id}/qualified
Devuelve solo el sello de la prueba, o null si todavía no tiene. No emite nada ni gasta sellos.
Parámetros
-
idobligatorio - El
idde la prueba.
Respuestas
- 200
proof_idyqualified.- 401
unauthorized.- 404
not_found.
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"proof_id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"qualified": {
"state": "issued",
"authority": "FNMT-RCM",
"time": "2026-09-30T09:12:05.000Z",
"serial_number": "175755C77B4239226AA0428FE1C107C1",
"policy_oid": "0.4.0.2023.1.1",
"tsr_url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr"
}
} Descargar el token (.tsr)
GET /proofs/{id}/qualified.tsr
El sello tal como lo devolvió la autoridad: una respuesta RFC 3161 (TimeStampResp) en DER. Es el archivo que un perito o un tribunal puede validar sin Sellat.
Parámetros
-
idobligatorio - El
idde la prueba.
Respuestas
- 200
- El
.tsr(application/timestamp-reply). - 401
unauthorized.- 404
not_found: la prueba no existe o todavía no tiene sello.
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/qualified.tsr \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-o seal.tsr HTTP/1.1 200 OK
Content-Type: application/timestamp-reply
Content-Disposition: attachment; filename="sellat-6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e-qualified-timestamp.tsr"
<RFC 3161 TimeStampResp, DER> Certificado y evidencias
Certificado en PDF
GET /proofs/{id}/certificate.pdf
El certificado de la prueba, para personas: la huella, la fecha, los anclajes y el sello cualificado si lo tiene, con las instrucciones para verificarlo.
Parámetros
-
idobligatorio - El
idde la prueba. -
langopcional - Idioma del certificado:
es,en,deofr. Cualquier otro valor daen.
Respuestas
- 200
- El PDF.
- 401
unauthorized.- 404
not_found.- 409
conflict: esos bytes los registró primero otra cuenta y la prueba no tiene certificado propio.
curl "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/certificate.pdf?lang=es" \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-o certificate.pdf HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="certificado-3b1d7e42-9c5a-4f0e-b8d6-1a2c3e4f5a6b.pdf"
<PDF> Paquete de evidencias
GET /proofs/{id}/evidence.zip
Un ZIP con lo necesario para defender la prueba sin Sellat: el certificado, el proof.json, el sello y el certificado de la autoridad si lo tiene, las instrucciones y, si está en custodia, el original.
Parámetros
-
idobligatorio - El
idde la prueba. -
langopcional - Idioma de los textos del paquete:
es,en,deofr.
Respuestas
- 200
- El ZIP.
- 401
unauthorized.- 404
not_found.- 409
conflict: esos bytes los registró primero otra cuenta.
Incluir el original gasta una de las descargas del día. Si ya no te quedan, el paquete sale sin él y el README lo dice.
curl "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/evidence.zip?lang=es" \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-o evidence.zip HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment; filename="sellat-evidencia-3b1d7e42-9c5a-4f0e-b8d6-1a2c3e4f5a6b.zip"
<ZIP> Custodia del original
Depositar el original
PUT /proofs/{id}/original
Guarda el archivo junto a su prueba, en servidores de la Unión Europea. Sellat vuelve a calcular la huella de lo que recibe y lo rechaza si no coincide con la prueba.
Envía los bytes tal cual, con el Content-Type del archivo, o como multipart/form-data en el campo file. POST funciona igual que PUT.
Parámetros
-
idobligatorio - El
idde la prueba. -
fileobligatorio - El archivo. Hasta 10 MB con la cuenta gratuita y 50 MB con la Cuenta Pro, y como mucho 25 MB por petición.
Respuestas
- 201
- Guardado. Devuelve la prueba con
original. - 200
- Ya estaba guardado.
- 400
invalid_request: el cuerpo está vacío o no se puede leer.- 401
unauthorized.- 404
not_found.- 409
hash_mismatch(no es el archivo de la prueba) oconflict(bytes de otra cuenta).- 413
file_too_large: supera el límite por archivo de tu plan. Traemax_file_bytes.- 502
unavailable: el almacenamiento no respondió.- 503
custody_unavailable.- 507
custody_quota_exceeded: no queda espacio en tu cuenta. Traeused_bytesymax_account_bytes.
La custodia es opcional: la prueba vale igual sin el original. Custodiarlo añade conservación, no la condiciona.
curl -X PUT https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-H "Content-Type: application/pdf" \
--data-binary @contract.pdf {
"id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"state": "anchored",
"original": {
"stored": true,
"file_name": "contract.pdf",
"size_bytes": 184320,
"mime_type": "application/pdf",
"stored_at": "2026-09-30T09:15:10.000Z",
"url": "https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original"
}
} Descargar el original
GET /proofs/{id}/original
Devuelve el archivo custodiado. Sellat recalcula su huella al servirlo y no lo entrega si ya no coincide. Cada descarga cuenta para el límite diario de tu plan; la cabecera X-Sellat-Custody-Downloads-Remaining dice cuántas te quedan.
Parámetros
-
idobligatorio - El
idde la prueba.
Respuestas
- 200
- El archivo, con su tipo y su nombre.
- 401
unauthorized.- 404
- No hay original en custodia.
- 409
conflict: el original todavía no está guardado.- 429
download_quota_exceeded: límite diario de descargas. Se reinicia a las 00:00 UTC.- 500
integrity_failed: lo guardado ya no coincide con la huella.- 502
unavailable.
curl https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original \
-H "Authorization: Bearer $SELLAT_API_TOKEN" \
-o contract.pdf HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="contract.pdf"
X-Sellat-Custody-Downloads-Remaining: 9
<the original bytes> Terminar la custodia
DELETE /proofs/{id}/original
Borra el original custodiado. La prueba no cambia: sigue anclada, sellada y verificable.
Parámetros
-
idobligatorio - El
idde la prueba.
Respuestas
- 200
"original": nully"proof_unaffected": true."purged": falsequiere decir que el borrado físico está en cola.- 401
unauthorized.- 404
- No hay original en custodia.
curl -X DELETE https://sellat.app/api/v2/proofs/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e/original \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"proof_id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"original": null,
"purged": true,
"proof_unaffected": true
} Cuenta
Tu cuenta
GET /account
Lo que puede hacer la clave que llama: el plan, los sellos que te quedan (de bienvenida y de packs), el espacio y las descargas de custodia, las pruebas de hoy y su límite, y las claves activas. Consúltalo antes de un lote grande.
El bloque connector son los límites de las tiendas conectadas (WooCommerce, próximamente).
Respuestas
- 200
- La cuenta.
- 401
unauthorized.
curl https://sellat.app/api/v2/account \
-H "Authorization: Bearer $SELLAT_API_TOKEN" {
"plan": "free",
"plan_name": "Free",
"seals": {
"available": true,
"remaining": 1,
"welcome_remaining": 1,
"pack_remaining": 0,
"price_eur": 6,
"buy_url": "https://sellat.app/precios"
},
"custody": {
"available": true,
"used_bytes": 0,
"max_account_bytes": 52428800,
"max_file_bytes": 10485760,
"downloads_used_today": 0,
"max_downloads_per_day": 10
},
"proofs": {
"daily_limit": 10,
"used_today": 3,
"resets_in_seconds": 41231
},
"connector": {
"mode_available": "daily",
"eidas_available": false,
"custody_available": false,
"operations": {
"daily_limit": 2000,
"resets_in_seconds": 41231
}
},
"keys": {
"active": 1
},
"urls": {
"dashboard": "https://sellat.app/dashboard",
"plans": "https://sellat.app/precios#pricing-business",
"seals": "https://sellat.app/precios#pricing-seal-title",
"docs": "https://sellat.app/developers/docs",
"connect": "https://sellat.app/connect/woocommerce"
}
} Prueba portable
Prueba portable (proof.json)
GET /proof/{id}.json Sin clave
El documento que permite verificar la prueba sin Sellat, en el formato público sellat-proof/2: la huella, la hoja, la ruta Merkle, la raíz, el anclaje en Polygon y los atestados (Bitcoin y el sello cualificado). Es público a propósito: quien lo tenga puede comprobar la prueba sin cuenta.
Parámetros
-
idobligatorio - El
idde la prueba.
Respuestas
- 200
- El
proof.json. - 202
- Todavía no está anclada:
{"ready": false, "state": "..."}conRetry-After: 60. - 400
- El
idno tiene formato de UUID. - 404
- No existe.
curl https://sellat.app/api/v2/proof/6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e.json -o proof.json {
"schema": "sellat-proof/2",
"proof_id": "6f2c9b1e-0d1a-4b9f-8e7c-2a4d5b6c7d8e",
"content": {
"algorithm": "SHA-256",
"hash": "9f3c2a5e0b7d1c4f8a6e2d9b3c7f1a5e8d2c6b0f4a9e3d7c1b5f8a2e6d0c4b9f"
},
"leaf": {
"formula": "SHA-256('sellat-leaf:v2:' + proof_id + ':' + content.hash)",
"value": "31668b4d846680cd920a1cb5be200ab0562909e8778223087c1738746a1cbb26"
},
"merkle": {
"index": 1,
"path": [
{
"position": "left",
"hash": "9e246a6d6dda91ee3916e149d834cd9a140e3470fbf5b6ec67824705dbbc82d4"
}
],
"root": "88fa1c4c3587d86d6f713e438c7ae745a91a6e03a5dd1b8282f17f35f30bfa14"
},
"anchors": [
{
"chain_id": 137,
"network": "Polygon Mainnet",
"tx_hash": "0xa4195d4ea808610dee92a1caa221d35f289e61674f451c82f7428e29813f9d6a",
"block_number": 94653624,
"payload": "sellat:v2:88fa1c4c3587d86d6f713e438c7ae745a91a6e03a5dd1b8282f17f35f30bfa14"
}
],
"attestations": [
{
"type": "opentimestamps",
"state": "submitted"
},
{
"type": "rfc3161-qualified-timestamp",
"state": "issued"
}
]
} ¿Te falta algo o necesitas más volumen? Escríbenos a [email protected]: hablarás con quien ha escrito el código.