API de Certificación y Trazabilidad
Certifica documentos y registra la trazabilidad de productos en la blockchain de Kaspa.
https://proovik.com/api/certify
https://proovik.com/api/trace
key Autenticación
Todas las peticiones deben incluir tu API Key en el header Authorization.
Obtén tu API Key desde la sección API en tu Panel de Usuario.
POST Certificar Hash
Certifica un hash SHA-256 en la blockchain, obteniendo un sello de tiempo inmutable.
Body (JSON):
{
"hash": "a1b2c3d4e5f6...64chars", // Hash SHA-256 del documento
"description": "Contrato v2.1", // Opcional: descripción
"email": "[email protected]" // Opcional: para notificaciones
}
Respuesta exitosa:
{
"success": true,
"txId": "kaspa:qr1234...txid",
"timestamp": "2026-01-15T10:30:00Z",
"explorerUrl": "https://explorer.kaspa.org/txs/..."
}
GET Verificar Certificado
Verifica si un hash ya ha sido certificado y obtiene su información.
Respuesta (hash encontrado):
{
"exists": true,
"timestamp": "2026-01-15T10:30:00Z",
"txId": "kaspa:qr1234...txid",
"description": "Contrato v2.1",
"merkle_proof": ["hash1", "hash2", ...]
}
Respuesta (hash no encontrado):
{
"exists": false
}
GET Descargar Certificado PDF
Descarga el certificado en formato PDF con toda la información de verificación.
Retorna un PDF con: hash, timestamp, txid, Merkle proof, QR de verificación.
Proof de Certificación
Endpoint: /api/certify/proof?hash={sha256_hash}
Obtiene la prueba criptográfica Merkle de una certificación. Requiere autenticación con API key y solo devuelve certificaciones de tu cuenta.
Ejemplo Request
curl -X GET "https://example.com/api/certify/proof?hash=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" \
-H "Authorization: Bearer YOUR_API_KEY"
Ejemplo Response
{
"success": true,
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"status": "success",
"created_at": "2026-01-15T10:30:00+00:00",
"confirmed_at": "2026-01-15T10:35:00+00:00",
"txid": "kaspa:abc123...",
"explorer_url": "https://explorer.kaspa.org/txs/kaspa:abc123...",
"anchored": true,
"merkle_proof": [
{"hash": "abc123...", "position": "left"},
{"hash": "def456...", "position": "right"}
],
"merkle_root": "d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"
}
Crear Nuevo Lote
Endpoint: /api/trace/batch
Registra un nuevo lote de productos en el sistema de trazabilidad.
Parámetros del Body (JSON)
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| product_name | string | Sí | Nombre del producto |
| gtin | string | No | Código GTIN/EAN-13 (puede repetirse entre lotes) |
| sgtin | string | No | Identificador serializado ⚠️ ÚNICO |
| origin | string | No | Ubicación de origen |
| quantity | number | No | Cantidad inicial |
| quantity_unit | string | No | Unidad (bottles, kg, L, etc.) |
| metadata | object | No | Datos adicionales (libre) |
sgtin debe ser único en todo el sistema. Si intentas crear un lote con un SGTIN que ya existe, recibirás error 409 Conflict:
{"success": false, "error": "SGTIN already exists. Each serialized batch must have a unique SGTIN."}
Ejemplo Request
curl -X POST https://proovik.com/api/trace/batch \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_name": "Aceite de Oliva Virgen Extra 500ml",
"gtin": "8412345678901",
"sgtin": "8412345678901.LOT20260114",
"origin": "Jaén, Andalucía",
"quantity": 5000,
"quantity_unit": "bottles",
"metadata": {
"producer": "Acme Foods S.L.",
"variety": "Picual",
"harvest_year": 2025
}
}'
Ejemplo Response (201 Created)
{
"success": true,
"batch_id": "BATCH-20260114-A1B2C3D4",
"id": 1,
"payload_hash": "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069",
"created_at": "2026-01-14T21:00:00+00:00"
}
Agregar Evento
Endpoint: /api/trace/event
Registra un cambio de estado, ubicación o transformación del lote. Los eventos se encadenan criptográficamente.
Parámetros del Body (JSON)
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| batch_id | string | Sí | ID del lote (BATCH-...) |
| event_type | string | Sí | COMMISSION, OBSERVE, SHIP, RECEIVE, TRANSFORM |
| location | object | No | {name, gln, lat, lng} |
| actor | object | No | {name, id, role} |
| data | object | No | Datos específicos del evento |
| evidence_hash | string | No | Hash de documento adjunto |
| gs1_bizstep | string | No | Business step GS1 EPCIS |
Ejemplo: Evento COMMISSION (Cosecha/Producción)
curl -X POST https://proovik.com/api/trace/event \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"batch_id": "BATCH-20260114-A1B2C3D4",
"event_type": "COMMISSION",
"location": {
"name": "Finca Los Olivos",
"gln": "8412345000001",
"lat": 37.7796,
"lng": -3.7849
},
"actor": {
"name": "Juan García Pérez"
},
"data": {
"action": "harvest",
"weight_kg": 25000,
"olive_variety": "Picual"
}
}'
Ejemplo Response (201 Created)
{
"success": true,
"event_id": 1,
"sequence": 1,
"event_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"prev_event_hash": "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069",
"status": "pending",
"message": "Event recorded. Will be anchored to blockchain in next Merkle batch."
}
prev_event_hash del primer evento enlaza al payload_hash del lote, formando una cadena completa: Batch → Evento1 → Evento2 → ...
Esto garantiza que modificar el lote romperá la verificación de toda la cadena.
Obtener Lote con Eventos
Endpoint: /api/trace/batch/{batch_id}
Recupera toda la información del lote y su cadena completa de eventos.
Ejemplo Response
{
"success": true,
"batch": {
"batch_id": "BATCH-20260114-A1B2C3D4",
"product_name": "Aceite de Oliva Virgen Extra 500ml",
"gtin": "8412345678901",
"origin": "Jaén, Andalucía",
"event_count": 3,
"is_complete": false
},
"events": [
{
"id": 1, "sequence": 1, "type": "COMMISSION",
"hash": "e3b0c442...", "status": "confirmed",
"txid": "kaspa:abc123..."
},
{
"id": 2, "sequence": 2, "type": "OBSERVE",
"hash": "d4735e3a...", "prev_hash": "e3b0c442...",
"status": "confirmed"
}
],
"chain_valid": true
}
Verificar Integridad
Endpoint: /api/trace/verify/{batch_id}
Verificación completa end-to-end: integridad del lote, cadena de eventos, y pruebas Merkle.
- Batch Integrity: Verifica SHA256(payload) == payload_hash
- Chain Integrity: Verifica prev_hash enlaces entre eventos
- Merkle Proofs: Recalcula matemáticamente proofs contra blockchain
- Timestamp Logic: Detecta inconsistencias temporales (ej: RECEIVE antes de SHIP)
Ejemplo Response
{
"success": true,
"batch_id": "BATCH-20260115-A1B2C3D4",
"product_name": "Aceite Oliva Premium",
"verification": {
"overall_valid": true,
"batch_integrity": {
"valid": true,
"payload_hash_matches": true,
"merkle_proof_valid": true,
"anchoring_status": "confirmed",
"errors": []
},
"chain_integrity": {
"valid": true,
"errors": []
},
"merkle_proofs": {
"batch_valid": true,
"events_valid": true,
"events_with_proof": 3,
"total_events": 3,
"errors": []
},
"total_events": 3,
"confirmed_events": 3,
"pending_events": 0,
"fully_verified": true
},
"blockchain_anchoring": {
"batch_anchored": true,
"batch_txid": "kaspa:abc123...",
"batch_merkle_root": "fb12c587..."
},
"verified_at": "2026-01-15T20:45:00+00:00"
}
Buscar por GTIN/SGTIN
Endpoint: /api/trace/search
Busca lotes usando identificadores estándar de la industria. No requiere autenticación (endpoint público para verificación).
gtin- Código GTIN/EAN-13 (búsqueda exacta)sgtin- Identificador serializado (búsqueda exacta)lot- ID de lote o parte del mismoproduct- Nombre del producto (búsqueda parcial)
Ejemplo Request
curl "https://proovik.com/api/trace/search?gtin=8412345678901" # O buscar por nombre de producto curl "https://proovik.com/api/trace/search?product=aceite"
Ejemplo Response
{
"success": true,
"count": 2,
"query": {"gtin": "8412345678901"},
"results": [
{
"batch_id": "BATCH-20260115-A1B2C3D4",
"product_name": "Aceite de Oliva Virgen Extra",
"gtin": "8412345678901",
"sgtin": "8412345678901.LOT2026",
"origin": "Jaén, Andalucía",
"event_count": 5,
"created_at": "2026-01-15T10:30:00Z",
"anchored": true,
"verification_url": "/verify/BATCH-20260115-A1B2C3D4"
}
]
}
Merkle Proof (Evento)
Endpoint: /api/trace/event/{event_id}/proof
Obtiene la prueba criptográfica Merkle de un evento de trazabilidad. Requiere autenticación con API key.
Ejemplo Response
{
"event_id": "EVT-20260115-ABC123",
"event_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"event_type": "SHIP",
"sequence": 3,
"status": "confirmed",
"merkle_batch_id": 42,
"merkle_root": "d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35",
"merkle_proof": [
{"hash": "abc123...", "position": "left"},
{"hash": "def456...", "position": "right"}
],
"txid": "kaspa:abc123...",
"explorer_url": "https://explorer.kaspa.org/txs/kaspa:abc123...",
"anchored": true
}
Merkle Proof (Lote)
Endpoint: /api/trace/batch/{batch_id}/proof
Obtiene la prueba criptográfica Merkle del lote. Demuestra cuándo se creó el lote y que no ha sido modificado.
Ejemplo Request
curl -X GET "https://example.com/api/trace/batch/BATCH-20260115-A1B2C3D4/proof" \
-H "Authorization: Bearer YOUR_API_KEY"
Ejemplo Response
{
"batch_id": "BATCH-20260115-A1B2C3D4",
"payload_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"created_at": "2026-01-15T10:30:00+00:00",
"anchoring_status": "confirmed",
"merkle_batch_id": 42,
"merkle_root": "fb12c587181bfae9a8575028c4e4d3c8df6508d407cbcb15b056c1f7f20779c2",
"merkle_proof": {
"merkle_root": "fb12c587...",
"leaf_index": 0,
"siblings": [
{"hash": "abc123...", "position": "right"},
{"hash": "def456...", "position": "left"}
],
"txid": "kaspa:abc123...",
"generated_at": "2026-01-15T10:35:00+00:00"
},
"txid": "kaspa:abc123...",
"explorer_url": "https://explorer.kaspa.org/txs/kaspa:abc123...",
"anchored": true
}
Tipos de Evento (GS1 EPCIS)
| Tipo | Uso | Ejemplo |
|---|---|---|
| COMMISSION | Creación/Inicio del producto | Cosecha, fabricación |
| OBSERVE | Inspección sin cambio de custodia | Control calidad, certificación |
| SHIP | Envío a otra ubicación | Salida de almacén |
| RECEIVE | Recepción de envío | Llegada a destino |
| TRANSFORM | Transformación física | Procesado, envasado |
| AGGREGATE | Agrupar lotes hijos en contenedor | Botellas → Caja, Cajas → Pallet |
| DISAGGREGATE | Desagrupar lotes de contenedor | Abrir pallet o caja |
📦 Ejemplo: Agregación Jerárquica
Request AGGREGATE
{
"batch_id": "PALLET-001",
"event_type": "AGGREGATE",
"data": {
"child_batch_ids": ["CAJA-001", "CAJA-002", "CAJA-003"]
},
"location": {"name": "Almacén Central"}
}
Response
{
"success": true,
"event_id": 15,
"event_type": "AGGREGATE",
"affected_batches": ["CAJA-001", "CAJA-002", "CAJA-003"],
"children_count": 3,
"message": "3 batches aggregated to PALLET-001"
}
payload_hash de cada hijo. Si alguien modifica un hijo después del agregado, la verificación fallará.
🔀 División de Lotes (Batch Splitting)
Permite dividir un lote en múltiples lotes hijos manteniendo la genealogía.
Request TRANSFORM (split)
{
"batch_id": "LOTE-5000L",
"event_type": "TRANSFORM",
"data": {
"transform_type": "split",
"output_batches": [
{"product_name": "Camión A", "quantity": 2500, "quantity_unit": "L"},
{"product_name": "Camión B", "quantity": 2500, "quantity_unit": "L"}
]
},
"location": {"name": "Centro Distribución"}
}
Response
{
"success": true,
"event_type": "TRANSFORM",
"transform_type": "split",
"source_batch": {
"batch_id": "LOTE-5000L",
"is_complete": true
},
"output_batches": [
{"batch_id": "BATCH-20260116-XXXXX", "split_ratio": 0.5},
{"batch_id": "BATCH-20260116-YYYYY", "split_ratio": 0.5}
]
}
is_complete: true y no acepta más eventos.
source_batch_id y evento COMMISSION automático enlazado al TRANSFORM original.
Cadena de Hash Completa
La cadena de integridad comienza desde el lote y enlaza cada evento al anterior:
Si alguien modifica el lote o cualquier evento, los hashes no coincidirán y la verificación fallará automáticamente.
Anclaje a Blockchain
Los eventos se anclan periódicamente a la blockchain de Kaspa mediante un Merkle Tree:
- Se agrupan los hashes de eventos pendientes
- Se calcula un Merkle Root (hash raíz)
- El Merkle Root se registra en una transacción de Kaspa
- Cada evento recibe un merkle_proof y el txid
pending →
batched →
confirmed