ORBITAL GRID API
Una sola API sobre los satélites de observación terrestre del mundo. Describís qué necesitás — área, fechas, tipo de dato, resolución, tolerancia a nubes — y el motor de ruteo elige el mejor satélite, consulta el catálogo real y hace auto-switch cuando hace falta (incluido óptico→SAR cuando las nubes tapan la vista).
Base URL: …
Qué es ORBITAL GRID
- Un registry de satélites con tres estados honestos:
live(datos reales ya),requires_credential(conector listo, se activa al configurar la key) ypending_agreement(comercial, a la espera de convenio). - Un motor de ruteo que puntúa cada satélite capaz y explica por qué eligió el que eligió, con la traza completa de auto-switch.
- Una capa de inteligencia que convierte una pregunta de negocio en español en parámetros técnicos.
- Una capa de analytics que convierte imágenes en respuestas. Primer producto: detección de campos sembrados con radar SAR (motor Sembra).
Quickstart
1. Creá tu API key self-service en /portal (nombre + email; la key se muestra una sola vez).
2. Hacé tu primera llamada:
curl -s -X POST {{BASE}}/v1/intent \
-H "Content-Type: application/json" \
-H "X-API-Key: TU_API_KEY" \
-d '{"query":"humedad de mis campos de soja en Pergamino en la última semana"}'
import httpx
r = httpx.post(
"{{BASE}}/v1/intent",
headers={"X-API-Key": "TU_API_KEY"},
json={"query": "humedad de mis campos de soja en Pergamino en la última semana"},
timeout=60,
)
data = r.json()
print(data["selected_satellite"], "→", data["explanation"])
const r = await fetch("{{BASE}}/v1/intent", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": "TU_API_KEY" },
body: JSON.stringify({ query: "humedad de mis campos de soja en Pergamino en la última semana" }),
});
const data = await r.json();
console.log(data.selected_satellite, data.explanation);
3. Explorá el contrato completo en /docs (OpenAPI interactivo).
Autenticación
Todos los endpoints de datos requieren el header X-API-Key. Las keys se emiten en el portal de clientes, se muestran una única vez y se guardan hasheadas del lado del servidor.
Cada key tiene un rate limit por minuto según su plan, y su uso queda medido por endpoint y por día — lo consultás en /v1/account/usage.
POST /v1/portal/keys/revoke y emití una nueva.Salud de la plataforma
Estado del servicio, conteos del registry y alcanzabilidad de cada catálogo upstream (probado de verdad, con caché corto).
curl -s {{BASE}}/health
import httpx
print(httpx.get("{{BASE}}/health", timeout=30).json())
const h = await (await fetch("{{BASE}}/health")).json();
console.log(h.status, h.catalogs);
El registry de satélites
Todos los satélites registrados con sus capacidades y estado de acceso.
| Query param | Valores | Descripción |
|---|---|---|
data_type | optical · multispectral · sar · thermal · atmospheric · elevation | Filtra por tipo de dato. |
access | live · requires_credential · pending_agreement | Filtra por estado de acceso. |
cost_tier | free · commercial | Filtra por costo del dato. |
curl -s "{{BASE}}/v1/satellites?data_type=sar&access=live"
import httpx
sats = httpx.get("{{BASE}}/v1/satellites",
params={"data_type": "sar", "access": "live"}, timeout=30).json()
print(sats["count"], "satélites SAR live")
const s = await (await fetch("{{BASE}}/v1/satellites?data_type=sar&access=live")).json();
console.log(s.count, "satélites SAR live");
Búsqueda unificada de imágenes
El corazón de la plataforma: una búsqueda estructurada sobre todos los satélites. El motor puntúa candidatos, consulta el mejor catálogo y auto-switchea si viene vacío.
| Campo | Tipo | Descripción |
|---|---|---|
bbox | [w,s,e,n] | AOI como bounding box WGS84 (esto o geometry). |
geometry | GeoJSON | AOI como geometría GeoJSON. |
datetime_from / datetime_to | ISO-8601 | Rango de fechas. |
data_type | enum | optical · multispectral · sar · thermal · atmospheric · elevation. |
max_resolution_m | float | GSD más grueso aceptable. |
cloud_cover_max | 0–100 | Máximo % de nubes (óptico). |
priority | enum | recency · resolution · cost. |
allow_sar_fallback | bool | Si el óptico no encuentra nada bajo el tope de nubes, cambia a SAR (default true). |
limit | int | Máx. escenas (1–50). |
curl -s -X POST {{BASE}}/v1/imagery/search \
-H "Content-Type: application/json" -H "X-API-Key: TU_API_KEY" \
-d '{"bbox":[-60.70,-34.00,-60.50,-33.80],
"datetime_from":"2026-04-01","datetime_to":"2026-07-06",
"data_type":"optical","max_resolution_m":30,
"cloud_cover_max":20,"priority":"resolution","limit":3}'
import httpx
r = httpx.post("{{BASE}}/v1/imagery/search",
headers={"X-API-Key": "TU_API_KEY"},
json={"bbox": [-60.70, -34.00, -60.50, -33.80],
"datetime_from": "2026-04-01", "datetime_to": "2026-07-06",
"data_type": "optical", "max_resolution_m": 30,
"cloud_cover_max": 20, "priority": "resolution", "limit": 3},
timeout=120)
res = r.json()
print(res["selected_satellite"], res["selected_reason"])
for sc in res["scenes"]:
print(" ", sc["satellite"], sc["datetime"], sc.get("cloud_cover"))
const r = await fetch("{{BASE}}/v1/imagery/search", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": "TU_API_KEY" },
body: JSON.stringify({
bbox: [-60.70, -34.00, -60.50, -33.80],
datetime_from: "2026-04-01", datetime_to: "2026-07-06",
data_type: "optical", max_resolution_m: 30,
cloud_cover_max: 20, priority: "resolution", limit: 3,
}),
});
const res = await r.json();
console.log(res.selected_satellite, res.switched, res.switch_trace);
La respuesta incluye selected_satellite, selected_reason, switched + switch_trace (la historia del auto-switch), scenes normalizadas con links de preview/descarga, candidates_considered y catalogs_status.
Capa de inteligencia — lenguaje natural
Mandá una pregunta de negocio en español; ORBITAL GRID infiere AOI, tipo de dato, índices (NDVI/NDWI/NBR/SAR), ventana temporal, tolerancia a nubes y prioridad, rutea con el mismo motor y explica la decisión en español.
curl -s -X POST {{BASE}}/v1/intent \
-H "Content-Type: application/json" -H "X-API-Key: TU_API_KEY" \
-d '{"query":"mapa de inundación en Pehuajó después del temporal la última semana"}'
import httpx
r = httpx.post("{{BASE}}/v1/intent", headers={"X-API-Key": "TU_API_KEY"},
json={"query": "mapa de inundación en Pehuajó la última semana"},
timeout=120)
d = r.json()
print(d["interpretation"], d["selected_satellite"], d["explanation"], sep="\n")
const d = await (await fetch("{{BASE}}/v1/intent", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": "TU_API_KEY" },
body: JSON.stringify({ query: "mapa de inundación en Pehuajó la última semana" }),
})).json();
console.log(d.inferred_params, d.selected_satellite);
Capa de analytics
Catálogo de capacidades analíticas disponibles, con su cobertura procesada y métricas validadas — sin humo: lo que está listo, está listo; lo que no, se dice.
Detección de campos sembrados (SAR)
Primer producto analítico: detección de lotes sembrados con radar SAR (motor Sembra, SAOCOM banda L / Sentinel-1 banda C). Funciona con nubes, de día y de noche. Validado contra referencia óptica independiente: F1 = 0.9654 (Random Forest, cross-validation 5-fold, n=326).
| Campo | Tipo | Descripción |
|---|---|---|
bbox | [w,s,e,n] | AOI en WGS84. Obligatorio. |
min_confidence | 0–1 | Solo lotes con confianza ≥ este valor (default 0). |
include_geometry | bool | false = solo propiedades, sin polígonos (default true). |
curl -s -X POST {{BASE}}/v1/analytics/fields \
-H "Content-Type: application/json" -H "X-API-Key: TU_API_KEY" \
-d '{"bbox":[-60.65,-33.90,-60.60,-33.85],"min_confidence":0.8}'
import httpx
r = httpx.post("{{BASE}}/v1/analytics/fields",
headers={"X-API-Key": "TU_API_KEY"},
json={"bbox": [-60.65, -33.90, -60.60, -33.85], "min_confidence": 0.8},
timeout=60)
d = r.json()
if d["status"] == "delivered":
print(d["summary"]) # lotes sembrados / no sembrados
geojson = d["result"] # FeatureCollection listo para un mapa
else:
print(d["message"]) # AOI aún no procesada — respuesta honesta
const d = await (await fetch("{{BASE}}/v1/analytics/fields", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": "TU_API_KEY" },
body: JSON.stringify({ bbox: [-60.65, -33.90, -60.60, -33.85], min_confidence: 0.8 }),
})).json();
console.log(d.status, d.summary ?? d.message);
Respuesta delivered: resumen de lotes, métricas de validación, proveniencia de la escena SAR + referencia óptica, y el FeatureCollection GeoJSON con cada lote (label, confianza, RVI, backscatter). AOIs fuera de la cobertura procesada reciben accepted_on_demand con la cobertura disponible — nunca un resultado inventado.
Portal — crear una API key
Alta self-service. La key se devuelve una sola vez; guardala en un secret manager. También podés hacerlo visualmente en /portal.
curl -s -X POST {{BASE}}/v1/portal/signup \
-H "Content-Type: application/json" \
-d '{"name":"Mi Empresa","email":"dev@miempresa.com"}'
import httpx
r = httpx.post("{{BASE}}/v1/portal/signup",
json={"name": "Mi Empresa", "email": "dev@miempresa.com"}, timeout=30)
print(r.json()) # {"api_key": "og_live_…", …} — se muestra UNA vez
const k = await (await fetch("{{BASE}}/v1/portal/signup", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Mi Empresa", email: "dev@miempresa.com" }),
})).json();
console.log(k.api_key); // guardala YA: no se vuelve a mostrar
Cuenta y uso
Uso medido de tu key: total, hoy, por día (últimos 30) y por endpoint. Es la misma medición que alimenta la facturación.
Datos de la key: prefijo visible, plan, rate limit, fecha de alta.
Revoca la key con la que autenticás. Irreversible: emití una nueva desde el portal.
curl -s {{BASE}}/v1/account/usage -H "X-API-Key: TU_API_KEY"
import httpx
u = httpx.get("{{BASE}}/v1/account/usage",
headers={"X-API-Key": "TU_API_KEY"}, timeout=30).json()
print(u["usage"]["total"], "requests")
const u = await (await fetch("{{BASE}}/v1/account/usage",
{ headers: { "X-API-Key": "TU_API_KEY" } })).json();
console.log(u.usage.total, "requests");
Errores y límites
| Código | Significado | Qué hacer |
|---|---|---|
401 | Key faltante, inválida o revocada. | Verificá el header X-API-Key; emití una key en /portal. |
422 | Parámetros inválidos (bbox mal formado, enum desconocido…). | El detalle indica el campo exacto. |
429 | Rate limit de tu plan excedido. | Respetá el header Retry-After. |
503 | Capacidad temporalmente no disponible. | Reintentá con backoff; mirá /health. |
Los catálogos upstream pueden estar caídos: la plataforma lo reporta en catalogs_status y en /health en vez de inventar resultados.