API de Certificación y Trazabilidad

Certifica documentos y registra la trazabilidad de productos en la blockchain de Kaspa.

Certificación: https://proovik.com/api/certify
Trazabilidad: https://proovik.com/api/trace

key Autenticación

Todas las peticiones deben incluir tu API Key en el header Authorization.

Authorization: Bearer YOUR_API_KEY

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.

POST /api/certify

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/..."
}
Nota: Si incluyes API Key en el header, la certificación se asociará a tu cuenta. Sin API Key, se usa el sistema de cuota gratuita (3 certs/mes por dispositivo).

GET Verificar Certificado

Verifica si un hash ya ha sido certificado y obtiene su información.

GET /api/verify?hash={sha256_hash}

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.

GET /api/certificate?hash={sha256_hash}

Retorna un PDF con: hash, timestamp, txid, Merkle proof, QR de verificación.

GET

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.

Seguridad: Solo puedes obtener proofs de certificaciones realizadas con tu API key. Intentar acceder a certificaciones de otros usuarios devolverá 404.

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"
}
POST

Crear Nuevo Lote

Endpoint: /api/trace/batch

Registra un nuevo lote de productos en el sistema de trazabilidad.

Parámetros del Body (JSON)

CampoTipoRequeridoDescripción
product_namestringSíNombre del producto
gtinstringNoCódigo GTIN/EAN-13 (puede repetirse entre lotes)
sgtinstringNoIdentificador serializado ⚠️ ÚNICO
originstringNoUbicación de origen
quantitynumberNoCantidad inicial
quantity_unitstringNoUnidad (bottles, kg, L, etc.)
metadataobjectNoDatos adicionales (libre)
⚠️ Validación SGTIN: El campo 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"
}
POST

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)

CampoTipoRequeridoDescripción
batch_idstringSíID del lote (BATCH-...)
event_typestringSíCOMMISSION, OBSERVE, SHIP, RECEIVE, TRANSFORM
locationobjectNo{name, gln, lat, lng}
actorobjectNo{name, id, role}
dataobjectNoDatos específicos del evento
evidence_hashstringNoHash de documento adjunto
gs1_bizstepstringNoBusiness 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."
}
🔗 Cadena Completa: El 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.
GET

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
}
GET

Verificar Integridad

Endpoint: /api/trace/verify/{batch_id}

Verificación completa end-to-end: integridad del lote, cadena de eventos, y pruebas Merkle.

4 niveles de verificación:
  • 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"
}
GET

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.

Nota: Los eventos se anclan a blockchain cada 5 minutos. Si el proof no está disponible, espere unos minutos y vuelva a consultar.

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
}
GET

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.

Nota: Los lotes se anclan a blockchain cada 5 minutos junto con los eventos. El proof estará disponible después del siguiente ciclo de anclaje.

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)

TipoUsoEjemplo
COMMISSIONCreación/Inicio del productoCosecha, fabricación
OBSERVEInspección sin cambio de custodiaControl calidad, certificación
SHIPEnvío a otra ubicaciónSalida de almacén
RECEIVERecepción de envíoLlegada a destino
TRANSFORMTransformación físicaProcesado, envasado
AGGREGATEAgrupar lotes hijos en contenedorBotellas → Caja, Cajas → Pallet
DISAGGREGATEDesagrupar lotes de contenedorAbrir 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"
}
Integridad: El evento incluye los 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}
  ]
}
Lote original: Se marca como is_complete: true y no acepta más eventos.
Lotes hijos: Cada uno tiene 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:

📦 Lote
BATCH-2026...
payload_hash: 7f83b1...
→
Evento 1
COMMISSION
hash: e3b0c4...
prev: 7f83b1...
→
Evento 2
OBSERVE
hash: d4735e...
prev: e3b0c4...
→
Evento 3
SHIP
hash: 4e0740...
prev: d4735e...

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:

  1. Se agrupan los hashes de eventos pendientes
  2. Se calcula un Merkle Root (hash raíz)
  3. El Merkle Root se registra en una transacción de Kaspa
  4. Cada evento recibe un merkle_proof y el txid
Estados del evento: pending → batched → confirmed