EKIA Data Service

El modelo de evidencia

Esta es la página que explica qué hace distinto a este servicio: no sirve números, sirve observaciones — con su evidencia, su historia y una línea de tiempo consultable.

El problema

Un tipo de cambio alimenta asientos contables, facturas y declaraciones. Años después, un auditor pregunta: ¿de dónde salió este número? Si la API que lo sirvió solo entregaba el valor del día, no hay respuesta: el dato pudo cambiar, la fuente no expone histórico de sus correcciones y el rastro se perdió. Este servicio está construido para que esa pregunta siempre tenga respuesta.

La observación: inmutable por diseño

Cada vez que el servicio observa una fuente oficial y obtiene un valor nuevo, crea una observación: qué valor publicó la fuente (compra/venta, canónico y crudo), para qué fecha (fecha_serie), de qué fuente y con qué consulta exacta (identidad_consulta), en qué instante (capturado_en), con qué versión del parser, y con qué bytes crudos de respaldo (evidencia_id y el fragmento exacto del payload del que se parseó el valor).

Ninguno de esos campos se edita jamás. Si la fuente corrige un valor, el servicio no reescribe la observación: crea una nueva que la supersede y lo registra como evento. La observación corregida queda consultable para siempre en /v1/observations/{id}, con su cadena completa de ancestros y sucesoras. Un dato que usó en 2026 sigue explicable en 2036, aunque haya sido corregido en el camino.

La revisión: la línea de tiempo del dataset

Toda escritura al registro — una captura nueva, una recaptura idéntica, una corrección — avanza una revisión global del dataset. La revisión N es el estado del registro tras el commit número N: una línea de tiempo totalmente ordenada.

El parámetro as_of_revision de /v1/rates consulta el dataset como era a esa revisión. La respuesta es inmutable: puede pedirse hoy o dentro de diez años y son los mismos bytes (por eso viaja con Cache-Control: immutable y ETag).

Ejemplo: un auditor en 2028 reconstruye el 21 de agosto de 2026

Supongamos que en 2028 hay que demostrar qué se sabía del tipo de cambio del 21/08/2026 al terminar ese día. Paso 1: mapear el instante a una revisión.

curl -s -H "Authorization: Bearer $EKIA_TOKEN" \
  'https://api.eurekia.pe/v1/revisions?at=2026-08-21T23:59:59-05:00'
{
  "revision": 658,
  "ts_commit": "2026-08-22T03:17:11.877559Z",
  "dataset_revision": 711,
  "request_id": "57d47928-1818-4157-b075-5ea23454a4d8",
  "schema_version": "1.0"
}

Al cierre del 21/08/2026 en Lima regía la revisión 658. Paso 2: consultar las tasas ancladas a esa revisión.

curl -s -H "Authorization: Bearer $EKIA_TOKEN" \
  'https://api.eurekia.pe/v1/rates?currency=USD&series=publicado&from=2026-08-21&to=2026-08-26&as_of_revision=658'
{
  "items": [
    {
      "fecha_serie": "2026-08-21",
      "compra": "3.351",
      "venta": "3.361",
      "fuente": "sunat_txt",
      "cotejos": [],
      "tiene_discrepancia_abierta": false,
      "marcas": ["capturada", "recaptura_identica"],
      "observacion_id": "f39403ae-c387-4045-8091-c901973f8feb",
      "capturado_en": "2026-08-21T17:06:47.880642Z",
      "superseded": false,
      "superseded_por": null
    }
  ],
  "total": 1,
  "next_page_token": null,
  "dataset_revision": 658,
  "request_id": "3720caed-3e07-4246-ae1e-3e28f8ecb094",
  "schema_version": "1.0"
}

A la revisión 658 el registro conocía una fecha de ese rango (el 21/08); las capturas de los días siguientes ocurrieron en revisiones posteriores — exactamente lo que se sabía entonces, ni más ni menos. Dos detalles del ítem histórico:

La evidencia: verifique el hash usted mismo

Cada captura guarda los bytes exactos que la fuente respondió (el body HTTP descomprimido, tal cual llegó) y su SHA-256. /v1/evidence/{id} los devuelve. El siguiente ejemplo es real y ejecutable: descarga la evidencia de la observación del 21/08/2026 y verifica su hash. Fue ejecutado tal cual el 26/08/2026; las salidas son las reales.

curl -s -H "Authorization: Bearer $EKIA_TOKEN" \
  -D encabezados.txt -o evidencia.txt \
  https://api.eurekia.pe/v1/evidence/f4a7a1c6-e1a4-4999-b175-7191e90c77c6

cat evidencia.txt
# 21/08/2026|3.351|3.361|

sha256sum evidencia.txt
# 40dad22e26fe688bd700781111a10212e3725ae1bf9c14df92de36787f3d5a59  evidencia.txt

grep -i x-sha256 encabezados.txt
# x-sha256: 40dad22e26fe688bd700781111a10212e3725ae1bf9c14df92de36787f3d5a59

Los 24 bytes descargados son el tipoCambio.txt que SUNAT publicó ese día, y el hash calculado en su máquina coincide con el que el servicio registró al capturarlo. La observación (/v1/observations/f39403ae-…) referencia esta evidencia y el fragmento exacto del que se parseó el valor: la cadena valor → observación → bytes de la fuente queda cerrada.

Los cotejos: fuentes que se vigilan entre sí

Cuando existen observaciones de más de una fuente para la misma fecha, el servicio las coteja y publica el resultado (ok o discrepante) en el campo cotejos de cada ítem. Ante una discrepancia, el servicio no arbitra cuál fuente manda: la expone (tiene_discrepancia_abierta: true) y deja la decisión al consumidor.

Los límites, declarados

La honestidad del modelo incluye decir qué no prueba:

Qué guardar en su sistema

Dos campos por cada dato que tome: observacion_id y dataset_revision. Con ellos, cualquier número en su sistema se reconstruye años después: qué observación lo respaldaba, qué evidencia tenía y qué contenía el dataset cuando lo tomó.