Reportes por API
Actividad eléctrica, housing y peritaje de daños: evaluar primero, emitir el PDF después.
Reportes por API
Tres productos, una sola forma. Cada uno responde primero una pregunta barata, y si la respuesta te sirve, emitís el PDF firmado.
| Producto | La pregunta | El documento |
|---|---|---|
| Actividad eléctrica | ¿Hubo descargas cerca del punto en la ventana? | Informe GLM firmado |
| Housing | ¿Hay una edificación en el lote? | Informe de presencia |
| Peritaje de daños | ¿Cuánto daño dejó el evento? | Dossier con firma Ed25519 |
Evaluar no obliga a emitir. Es la decisión de diseño que ordena todo lo demás: preguntar cuesta poco, emitir cuesta más, y quién decide gastar sos vos.
Fuente del diagrama (mermaid)
sequenceDiagram
participant C as Cliente
participant S as SBOX
C->>S: POST /v1/lightning/evaluations
S-->>C: 200 · detected, coverage, flashes[]
Note over C: Evaluar no obliga a emitir
C->>S: POST /v1/lightning/reports { evaluationId }
S-->>C: 202 · Location /v1/jobs/{id}
C->>S: GET /v1/jobs/{id}/result
S-->>C: 200 · downloadUrl (firmada, 15 min)
S-)C: webhook report.ready (HMAC)
Autenticación
Una clave de API por Authorization: Bearer. Se acuña una sola vez desde la
consola y no se vuelve a mostrar: guardala al crearla.
curl -sS "$SBOX/v1/lightning/evaluations" \
-H "authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "content-type: application/json" \
-d '{"lat": -34.6, "lng": -58.4, "eventAt": "2026-01-15T18:30:00Z", "radiusKm": 20}'El alcance integracion:reportes cubre los tres productos y la administración
de tus webhooks con una sola clave.
Idempotency-Key
Obligatoria en todo lo que gasta cuota de un proveedor. Sin ella, un reintento
tuyo por timeout vuelve a pagar por la misma pregunta. Repetir la misma clave con
el mismo cuerpo devuelve el mismo resultado; con otro cuerpo devuelve 409.
1. Actividad eléctrica
POST /v1/lightning/evaluations
{ "lat": -34.6, "lng": -58.4, "eventAt": "2026-01-15T18:30:00Z", "radiusKm": 20, "windowMin": 15 }La respuesta distingue tres cosas que no son lo mismo:
coverage: "ok"condetected: true— hubo actividad.coverage: "ok"condetected: false— se miró y no había nada.coverage: "out_of_coverage" | "no_data"— no se pudo mirar.
Ese último caso no es "no hubo rayos". Es un hueco del archivo satelital o una fecha anterior a él, y tratarlo como ausencia sería afirmar algo que no se midió.
También podés mandar aoiRef en vez del punto y se usa el centroide del lote.
Para el PDF:
POST /v1/lightning/reports
{ "evaluationId": "ev_lgt_...", "locale": "es-AR" }Devuelve 202 con un job. El informe cita la evaluación que ya hiciste: no
vuelve a consultar el satélite, así que dos informes del mismo hecho no se
pueden contradecir.
2. Housing
POST /v1/housing/evaluations
{ "aoiRef": "aoi_...", "minConfidence": 0.7 }Responde hasBuilding, cuántas huellas, el área cubierta y la confianza máxima.
Dos límites que conviene tener presentes antes de tarifar con esto:
- Detecta huellas de edificación, no viviendas. Un galpón y una casa son la misma huella.
- El dataset es un snapshot de 2023-05. Una construcción posterior no aparece, y su ausencia no prueba que el lote esté vacío.
Los dos límites van impresos en el informe, no sólo acá.
3. Peritaje de daños
Este tiene un paso más, porque depende de que el satélite haya vuelto a pasar.
POST /v1/damage/feasibility
{ "aoiRef": "aoi_...", "peril": "granizo", "eventDate": "2026-01-15" }Esta llamada no gasta cuota: consulta el catálogo de escenas, no el motor de cálculo. Cinco respuestas posibles:
status | Qué hacer |
|---|---|
ready | Pedir el peritaje |
pending_post_imagery | Esperar. retryAfter estima cuándo (revisita ~5 días) |
cloud_blocked | La imagen está tapada. Si trae retryAfter, otra pasada puede venir mejor |
unsupported_peril | Ese peligro no deja firma espectral (p. ej. viento) |
invalid_event | La fecha no permite planificar la comparación |
Con ready:
POST /v1/damage/assessments
{ "aoiRef": "aoi_...", "peril": "granizo", "eventDate": "2026-01-15" }Y después POST /v1/damage/reports con el assessmentId.
Sequía no necesita imagen posterior: compara contra la climatología de años
anteriores, así que suele estar ready enseguida.
Trabajos asíncronos
Todo lo que emite un PDF devuelve 202 con un job:
GET /v1/jobs/{id} → estado
GET /v1/jobs/{id}/result → resultado, con la URL firmada del PDF
DELETE /v1/jobs/{id} → cancelarLa URL firmada vence a los 15 minutos. Es corta a propósito: una URL de horas es una credencial portable, y quien la reenvíe por mail comparte el documento con cualquiera que lea ese mail.
Webhooks
Para no poletear:
POST /v1/webhooks/subscriptions
{ "url": "https://tu-sistema/ucotron", "eventTypes": ["report.ready"] }El secreto de firma viaja una sola vez, en esa respuesta. Cada entrega llega con
x-ucotron-signature: t=<timestamp>,v1=<hmac>, y se verifica sobre
v1:<timestamp>:<cuerpo>.
El timestamp entra en la firma para que una entrega capturada no se pueda reenviar indefinidamente. Aceptamos una tolerancia de 5 minutos.
El evento no trae la URL del PDF. Un webhook termina en logs, proxies o un canal de Slack; el aviso dice que está listo y el documento lo pedís con tu credencial. El poll sigue siendo la fuente de verdad: una entrega perdida no significa que el reporte no exista.
Reintentos: tres intentos con backoff de 1 s, 5 s y 15 s. Un 4xx de tu endpoint
va directo al DLQ sin reintentar — el mismo cuerpo tres veces no se arregla— con
la excepción de 408 y 429, que hablan de tiempo y no de contenido.
Errores
RFC 7807 en todas las respuestas de error, con un retryable que te ahorra
mantener tu propia tabla de qué conviene reintentar.
Un detalle que importa: un recurso de otra organización contesta 404, igual
que una ruta que no existe, con el mismo cuerpo. No es un descuido — un 403
confirmaría que el recurso existe en algún lado, y esa confirmación alcanza para
enumerar carteras ajenas.